Экзотические имена для методов, констант, переменных и полей - ошибка или особенность?

после некоторой путаницы в комментариях к

I думал, что я превращаю в вопрос. Согласно руководству по PHP, допустимое имя класса должно совпадать с [a-zA-Z_ \ x7f- \ xff] [a-zA-Z0-9_ \ x7f- \ xff] * . Но, видимо, это не соблюдается, и не относится ни к чему другому:

define('π', pi());
var_dump(π);

class ␀ {
    private $␀ = TRUE;
    public function ␀()
    {
        return $this->␀;
    }
}

$␀ = new ␀;
var_dump($␀ );
var_dump($␀->␀());

работает нормально (хотя моя IDE не может отображать ␀). Может ли какой-нибудь эрудированный человек объяснить это мне? Можем ли мы использовать любой Unicode? И если да, то с каких пор? Не то чтобы я на самом деле хотел бы, чтобы использовал что-либо, кроме A-Za-z_ , но мне любопытно.

Пояснение: Я не после Regex для проверки класса имена, и я не знаю, использует ли PHP внутренне Regex, который он предлагает в руководстве. То, что меня смутило (и, по-видимому, других парней в связанном вопросе), заключается в том, почему такие вещи, как $ ☂ = 1 , могут вообще использоваться в PHP. Предполагалось, что PHP6 будет выпуском Unicode, но PHP6 находится в состоянии перерыва. Но если нет поддержки Unicode, почему я могу это сделать тогда?

35
задан Community 23 May 2017 в 12:02
поделиться

3 ответа

Этот вопрос начинается с упоминания имен классов в заголовке, но затем переходит к примеру, который включает экзотические имена для методов, констант, переменных и полей. На самом деле для них существуют разные правила. Давайте начнем с тех, которые не чувствительны к регистру.

Нечувствительные к регистру идентификаторы (имена классов и функций/методов)

Общим руководством здесь является использование только печатаемых символов ASCII. Причина в том, что эти идентификаторы нормализуются к их строчной версии, однако, это преобразование зависит от локали. Рассмотрим следующий файл PHP, закодированный в ISO-8859-1:

<?php
function func_á() { echo "worked"; }
func_Á();

Будет ли этот скрипт работать? Возможно. Это зависит от того, что вернет tolower(193), что зависит от локали:

$ LANG=en_US.iso88591 php a.php
worked
$ LANG=en_US.utf8 php a.php

Fatal error: Call to undefined function func_Á() in /home/glopes/a.php on line 3

Поэтому не стоит использовать не ASCII символы. Однако даже символы ASCII могут вызвать проблемы в некоторых локалях. См. это обсуждение. Вполне вероятно, что в будущем это будет исправлено путем создания независимого от локали нижнего регистра, работающего только с символами ASCII.

В заключение, если мы используем многобайтовые кодировки для этих нечувствительных к регистру идентификаторов, нас ждут проблемы. Дело не только в том, что мы не сможем воспользоваться преимуществами нечувствительности к регистру. Мы можем столкнуться с неожиданными коллизиями, поскольку все байты, составляющие многобайтовый символ, по отдельности переводятся в нижний регистр с помощью правил локали. Возможно, что два разных многобайтовых символа отображаются в одно и то же модифицированное представление потока байтов после применения правил локали для каждого из байтов.

Идентификаторы, чувствительные к регистру (переменные, константы, поля)

Здесь проблема менее серьезна, поскольку эти идентификаторы чувствительны к регистру. Однако они просто интерпретируются как байтовые потоки. Это означает, что если мы используем Unicode, мы должны последовательно использовать одно и то же представление байтов; мы не можем смешивать UTF-8 и UTF-16; мы также не можем использовать BOM.

Фактически, мы должны придерживаться UTF-8. За пределами диапазона ASCII, UTF-8 использует ведущие байты от 0xc0 до 0xfd, а последующие байты находятся в диапазоне от 0x80 до 0xbf, которые находятся в допустимом диапазоне согласно руководству. Теперь допустим, что мы используем символ "Ġ" в файле с кодировкой UTF-16BE. Он будет переведен как 0x01 0x20, поэтому второй байт будет интерпретирован как пробел.

То, что многобайтовые символы читаются как однобайтовые, конечно же, не является поддержкой Unicode вообще. PHP имеет некоторую поддержку многобайтовых символов в виде ключа компиляции "--enable-zend-multibyte" (начиная с PHP 5.4, поддержка многобайтовых символов компилируется по умолчанию, но отключена; вы можете включить ее с помощью zend.multibyte=On в php.ini). Это позволяет вам объявлять кодировку скрипта:

<?php
declare(encoding='ISO-8859-1');
// code here
?>

Он также будет обрабатывать BOM, которые используются для автоматического определения кодировки и не становятся частью вывода. Однако есть несколько недостатков:

  • Удар по производительности, как памяти, так и процессора. Он хранит представление скрипта во внутренней многобайтовой кодировке, что занимает больше места (и, похоже, хранит в памяти оригинальную версию), а также тратит некоторое количество CPU на преобразование кодировки.
  • Поддержка многобайтовых кодировок обычно не компилируется, поэтому она меньше тестируется (больше ошибок).
  • Проблемы переносимости между установками, в которых поддержка скомпилирована, и теми, в которых ее нет.
  • Относится только к этапу разбора; не решает проблему, описанную для идентификаторов, нечувствительных к регистру.

Наконец, существует проблема отсутствия нормализации - один и тот же символ может быть представлен разными кодовыми точками Unicode (независимо от кодировки). Это может привести к некоторым очень трудно отслеживаемым ошибкам.

44
ответ дан 27 November 2019 в 07:14
поделиться

Из официальной документации :

Имя класса может быть любой допустимой меткой, при условии, что это не зарезервированное слово PHP. Допустимое имя класса начинается с буквы или символа подчеркивания, за которым следует любое количество букв, цифр или символов подчеркивания. В качестве регулярного выражения это будет выглядеть так: ^ [a-zA-Z_ \ x80- \ xff] [a-zA-Z0-9_ \ x80- \ xff] * $ .

2
ответ дан 27 November 2019 в 07:14
поделиться

Ваш символ закодирован как 0x80 0x90 0xe2 или что-то вроде этого, поэтому он соответствует вашему regexp, когда не интерпретирует юникод (работает на одиночных байтах).

5
ответ дан 27 November 2019 в 07:14
поделиться
Другие вопросы по тегам:

Похожие вопросы: