Статьи

3 странных факта PHP, которые вы можете не знать

Нет сомнений: PHP — простой, гибкий и прощающий язык. Но он также может демонстрировать удивительное поведение. В этой статье я представлю некоторые «странные факты» и объясню, почему PHP дает результаты, которые он дает.

Неточность с плавающей точкой

Большинство из вас, вероятно, знают, что числа с плавающей точкой не могут действительно представлять все действительные числа. Кроме того, некоторые операции между двумя хорошо представленными числами могут привести к неожиданным ситуациям. Это потому, что конечная точность, с которой компьютеры представляют числа, влияет на не только PHP, но и все языки программирования. Неточности в задачах с плавающей запятой вызывали головную боль у программистов с самого начала дисциплины.

Об этом вопросе было сказано много слов, но одна из самых важных написанных статей — « Что должен знать каждый учёный-компьютерщик об арифметике с плавающей точкой» . Если у вас никогда не было возможности прочитать его, я настоятельно рекомендую вам это сделать.

Давайте посмотрим на этот очень маленький фрагмент:

<?php
echo (int) ((0.1 + 0.7) * 10);

Как вы думаете, что будет результатом? Если вы догадались 8, вы ошиблись бы … Извините, вы потеряли приз! Этот код на самом деле напечатает 7! Для тех, у кого есть Zend Certification, этот пример уже известен. Фактически, вы можете найти его в Zend PHP 5 Certification Study Guide .

Теперь посмотрим, почему это происходит. Первая выполненная операция:

0.1 + 0.7 // result is 0.79999999999

Результат арифметического выражения хранится внутри как 0,7999999, а не 0,8 из-за проблемы точности, и именно здесь начинается проблема.

Вторая выполненная операция:

0.79999999 * 10 = 7.999999999

Эта операция работает хорошо, но сохраняет ошибку.

Третья и последняя выполненная операция:

(int) 7.9999999 // result is 7

Выражение использует явное приведение. Когда значение конвертируется в int

Здесь следует отметить две интересные вещи:

  • Если вы разыгрываете число с floatint
  • Хотя процессор не знает, и мы на самом деле получили эту ошибку из-за ее неточностей, он работает в соответствии с математическим парадоксом, который утверждает, что 0,999 … равно 1 .

В заключение я хотел бы привести второе руководство по сертификации Zend PHP 5 :

Всякий раз, когда точность ваших вычислений является важным фактором для правильного функционирования вашего приложения, вы должны вместо этого использовать (sic) функции произвольной точности, предоставляемые расширением BCMath (вы можете найти его в своей копии руководства по PHP). встроенных типов данных PHP.

Как PHP «увеличивает» строки

Во время нашей повседневной работы мы пишем инструкции, которые выполняют операции увеличения / уменьшения, например:

 <?php
$a = 5;
$b = 6;
$a++;
++$b;

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

 <?php
$a = 1;
$b = 3;
echo $a++ + $b;
echo $a + ++$b;
echo ++$a + $b++;

Вы записали свои ответы? Хорошо. Давайте проверим их всех.

  4
 6
 7 

Не слишком сложно, правда? Теперь давайте немного поднимем планку. Вы когда-нибудь пытались увеличить строки? Попробуйте угадать, какой будет выход для следующего:

 <?php
$a = 'fact_2';
echo ++$a;

$a = '2nd_fact';
echo ++$a;

$a = 'a_fact';
echo ++$a;

$a = 'a_fact?';
echo ++$a;

Это не так просто на этот раз, не так ли? Давайте раскроем ответы.

  fact_3
 2nd_facu
 a_facu
 факт? 

Удивлены? Использование оператора приращения в строке, заканчивающейся цифрой, увеличивает букву (ту, которая следует за ней в алфавите, например, t -> u). Независимо от того, начинается ли строка цифрами или нет, последний символ изменяется. Но нет никакого эффекта, если строка заканчивается не буквенно-цифровым символом.

Это хорошо задокументировано официальной документацией об увеличении / уменьшении операторов, но большинство из вас, возможно, не читали его, потому что вы, вероятно, думали, что ничего особенного там не было. Должен признать, я думал то же самое до недавнего времени.

PHP следует соглашению Perl при работе с арифметическими операциями над символьными переменными, а не с Си. Например, в PHP и Perl $ a = ‘Z’; $ А ++; превращает $ a в ‘AA’, а в C a = ‘Z’; A ++; превращает a в ‘[‘ (значение ASCII в ‘Z’ равно 90, значение ASCII в ‘[‘ равно 91). Обратите внимание, что символьные переменные можно увеличивать, но не уменьшать, и даже в этом случае поддерживаются только простые символы ASCII (az и AZ). Увеличение / уменьшение других символьных переменных не имеет никакого эффекта, исходная строка не изменяется.

Тайна появления ценности

Вы настоящий мастер массивов в PHP, признайте это. Не стесняйся. Вы уже знаете все о том, как создавать, управлять и удалять массивы. Тем не менее, следующий пример может удивить вас с первого взгляда.

Часто вы работаете с массивами и должны искать, находится ли заданное значение в массиве. PHP имеет функцию для этого, in_array() Давайте посмотрим на это в действии:

 <?php
$array = array(
  'isReady' => false,
  'isPHP' => true,
  'isStrange' => true
);
var_dump(in_array('sitepoint.com', $array));

Какой будет выход? Делайте ваши ставки, и давайте проверим это.

  правда 

Разве это не немного странно? У нас есть ассоциативный массив, где все его значения логические, и если мы ищем строку, мы получаем true Это значение волшебным образом появилось? Давайте посмотрим на другой пример.

 <?php
$array = array(
  'count' => 1,
  'references' => 0,
  'ghosts' => 1
);
var_dump(in_array('aurelio', $array));

И что мы получаем …

  правда 

Еще раз функция in_array() Как это возможно?

Вы испытываете одну из лучших и худших, любимых и ненавистных функций PHP. PHP не является строго типизированным, и именно здесь начинается ошибка. Фактически, все следующие значения, если сравнивать в PHP, считаются одинаковыми, если вы не используете оператор идентификации:

  • 0
  • ложный
  • «»
  • «0»
  • ЗНАЧЕНИЕ NULL
  • Массив ()

По умолчанию функция in_array()"""0"true1 Следовательно, в первом примере мы получили истину, потому что 'sitepoint.com' == true'aurelio' == 0

Чтобы решить эту проблему, вы должны использовать третий и необязательный параметр in_array() Итак, если мы напишем:

 <?php
$array = array(
  'count' => 1,
  'references' => 0,
  'ghosts' => 1
);
var_dump(in_array('aurelio', $array, true));

мы, наконец, false

Выводы

В этой статье вы видели странное и неожиданное поведение, которое может возникнуть при использовании PHP. Уроки, которые можно извлечь из этих примеров:

  • Никогда не доверяйте числам с плавающей запятой
  • Дважды проверьте, какой тип данных вы используете, прежде чем использовать их в операциях
  • Помните о проблемах слабых сравнений и типов данных

Если вы опытный пользователь, вы, вероятно, уже знали его, но переподготовка никогда не бывает бесполезной.

Изображение через Fotolia