Что делать, если параметр «игла» функции strpos() содержит преобразованное целочисленное значение, которое нельзя применить в качестве порядкового значения любого символа?

Я использую PHP 7.2.8 на своем компьютере с операционной системой Windows 10.

Я наткнулся на следующий текст из описания Параметр 'needle' в функции strpos(), указанный в Руководстве по PHP:

needle
Если needle не является строкой, оно преобразуется в целое число и применяется как порядковый номер символа.

Из приведенного выше утверждения о параметре 'needle' я не понимаю, как работает функция strpos();, когда параметр "needle" функции strpos() содержит преобразованное целочисленное значение, которое нельзя применить как порядковое значение любого символа.

Может кто-нибудь объяснить фактическое значение утверждения из руководства, когда параметр «игла» функции strpos() содержит преобразованное целочисленное значение, которое не может быть применено в качестве порядкового значения любого символа в простой для понимания, простой и ясной форме. язык?

Для меня и других обучающихся людей было бы лучше, если бы вы могли предоставить пару подходящих примеров рабочего кода функции strpos(), где параметр «игла» функции strpos() содержит преобразованное целочисленное значение, которое не может быть применено в качестве порядкового значения любого символ.

Благодарю вас.


person PHPFan    schedule 22.08.2018    source источник
comment
stackoverflow.com/ вопросы/19174563/   -  person R. Chappell    schedule 22.08.2018
comment
@trincot: Пожалуйста, удалите дубликат с моего вопроса. Я уже упоминал вопрос, на который вы дали ссылку. Вы можете видеть в ответе на этот вопрос, что больше нет примеров рабочего кода, демонстрирующих, как работает функция strpos(), когда нестроковое значение задается в качестве параметра «иглы». В основном, я хочу понять эту вещь. Благодарю вас.   -  person PHPFan    schedule 22.08.2018
comment
Упомянутый вопрос имеет правильный ответ. Спросите себя: что возвращает ord("A")? Что возвращает strpos("CBA", ord("A"))? Что возвращает strpos("CBA", 65)? ...и т.д.   -  person trincot    schedule 22.08.2018
comment
@trincot: Предположим, если я дам какое-то значение, которое оценивается как десятичное значение больше 255 после преобразования, то какое кардинальное значение будет использоваться и как будет работать функция? Это мой вопрос. Итак, можете ли вы продемонстрировать это на каком-нибудь подходящем примере рабочего кода?   -  person PHPFan    schedule 22.08.2018
comment
Я вижу небольшое пространство для того, чтобы рассматривать это как отдельный вопрос, но тогда вам следует обновить его, чтобы выделить его, поскольку в его формулировке сейчас он дублируется. Если ваш фактический вопрос касается значения больше 255, вы должны задать его и пропустить все, что не связано с этим конкретным вопросом. Так что не спрашивайте, что такое порядковый номер (как вы делаете сейчас), так как это явно дублируется.   -  person trincot    schedule 22.08.2018
comment
@trincot: я полностью изменил свой вопрос. Теперь, пожалуйста, удалите повторяющийся знак на моем вопросе. Благодарю вас.   -  person PHPFan    schedule 22.08.2018
comment
Фактический ответ заключается в том, что любое значение (в пределах разумного), заданное как needle, будет преобразовано в char (внутренний тип данных C, размер которого составляет один байт). Преобразование будет зациклено (т. е. будут сохранены только 8 младших битов), что означает, что var_dump(strpos('foo', ord('o')+256)); даст 1 в качестве ответа, так же, как var_dump(strpos('foo', ord('o')));. Если вы снова зададите вопрос или этот вопрос будет открыт повторно, я дам соответствующие ссылки.   -  person MatsLindh    schedule 22.08.2018
comment
ord возвращает десятичное значение первого байта символа. Поэтому, если он больше 255, он вернет значение первого байта (от 0 до 255). Вы можете проверить это, выполнив код, подобный print_r(chr(ord("€")));. Обратите внимание, что он выводит â, потому что ord("€") оценивается как 226, а chr(226) возвращает â.   -  person Anthony    schedule 22.08.2018
comment
@MatsLindh - Интересно ... обратите внимание, что var_dump(strpos('€fo', ord('€')+256)); возвращает 0, как и ожидалось, но var_dump(strpos('â€fo', ord('€')+256)); возвращает 2 Таким образом, наличие двух › 255 символов, кажется, отбрасывает это.   -  person Anthony    schedule 22.08.2018
comment
И просто для ясности: тот же результат дается, когда для strpos предоставляется правильная строка, что означает, что strpos всегда выполняет преобразование порядкового номера, даже когда строка предоставляется для иглы: var_dump(strpos('â€fo', '€')); возвращает int(2) вместо int(1), так же, как передача целое число как игла.   -  person Anthony    schedule 22.08.2018
comment
Вы путаете многобайтовые символы с чем-то особенным - это не так. strpos рассматривать только отдельные байты, а не сами символы. Поскольку у вас есть многобайтовая кодовая точка UTF в качестве первой буквы во втором примере, перед знаком евро есть два байта, что дает 2 в качестве ответа.   -  person MatsLindh    schedule 22.08.2018
comment
@MatsLindh - я ничего не путаю. Я говорю, что strpos не даст надежного ответа с многобайтовыми строками. Если бы это было просто предназначено для указания позиции байта, оно называлось бы bytepos. Ясно, что если бы у кого-то была многобайтовая строка и ему нужно было бы знать позицию первого (нужна правильная позиция этого символа, а не просто проверка, существует ли он в строке), strpos не предоставил бы эту позицию надежно.   -  person Anthony    schedule 22.08.2018
comment
Или вы говорите, что знание того, что перед знаком евро есть 2 байта, более ценно (для целей усечения и т. д.), чем знание того, что перед ним есть один символ?   -  person Anthony    schedule 22.08.2018
comment
Это правильно. Ни одна из встроенных строковых функций PHP не работает с многобайтовыми строками. Все они используются для доступа к кодировкам строк с шириной в один байт (т. е. они не знают, какие символы фактически представляют собой, они просто сравнивают значения байтов). Знание того, что перед € есть два байта, полезно для извлечения подмножества байтов и т. д. — эти функции также используются для работы с байтами напрямую (и не думают о них как о строках). Модуль mbstring имеет mb_strpos для работы с кодировками многобайтовых строк.   -  person MatsLindh    schedule 22.08.2018
comment
Вопрос открыт после доработки. @MatsLindh, так как вы первыми дали правильные подсказки, пожалуйста, имейте в виду :)   -  person trincot    schedule 22.08.2018


Ответы (1)


Любое значение (в пределах разумного), указанное как игла , будет быть преобразован в char (внутренний тип данных C, размер которого составляет один байт). Соответствующий код из текущей реализации strpos:

/* {{{ php_needle_char
 */
static int php_needle_char(zval *needle, char *target)
{
    switch (Z_TYPE_P(needle)) {
        case IS_LONG:
            *target = (char)Z_LVAL_P(needle);
            return SUCCESS;
        case IS_NULL:
        case IS_FALSE:
            *target = '\0';
            return SUCCESS;
        case IS_TRUE:
            *target = '\1';
            return SUCCESS;
        case IS_DOUBLE:
            *target = (char)(int)Z_DVAL_P(needle);
            return SUCCESS;
        case IS_OBJECT:
            *target = (char) zval_get_long(needle);
            return SUCCESS;
        default:
            php_error_docref(NULL, E_WARNING, "needle is not a string or an integer");
            return FAILURE;
    }
}
/* }}} */

Это преобразование (char) будет повторяться (т. е. будут сохранены только 8 младших значащих битов), что означает, что var_dump(strpos('foo', ord('o') + 256)); даст 1 в качестве ответа, так же, как var_dump(strpos('foo', ord('o')));.

Имейте в виду, что любая из старых функций str* в PHP не поддерживает многобайтовую кодировку — они работают только с одиночными байтами. Строка в PHP представляет собой набор байтов (а не символов), и вызов strpos приведет к совпадению только одного байтового значения. Поэтому, если вы дадите ему строку с многобайтовой кодировкой, ваши результаты не будут иметь особого смысла.

Если вы используете многобайтовую кодировку, такую ​​как utf-8, модуль mbstring предоставляет копии большинства внутренних строковых функций при обработке многобайтовой кодировки. Для strpos эта функция называется mb_strpos.

PHP также поддерживал функциональность для переопределения имен внутренних функций их mb_* аналогами, но это поведение устарело, насколько я помню, и на него нельзя полагаться никоим образом, поскольку оно нарушает код неочевидными способами.

person MatsLindh    schedule 22.08.2018