Sunday, May 3, 2009

Неоднозначности PHP

За три месяца молчания накопились "прелести" PHP с которыми можно и поделиться.
Меньше слов больше консоли.

Для начала кусок докуметации о сравнении массивов


Для массивов $a и $b
$a == $b Равно TRUE в случае, если $a и $b содержат одни и те же элементы



php -a
php > $a = array(1,2);
php > $b = array(2,1);
php > var_dump($a == $b);
bool(false)


Для меня это оказалось несколько неожиданным изходя из документации, однако следущий код неожиданно вносит ясность.


php > class X {};
php > $x1 = new X();
php > $x2 = new X();
php > $a = array($x1, $x2);
php > $b = array($x2, $x1);
php > var_dump($a == $b);
bool(true)


В принципе все это объяснимо, во втором примере используются ссылки, и объекты (суть элементы) действительно одни и теже, в первом же используются числа и думаю во внутреннем представлении это все таки разные эелементы, но отсуствие концепции в целом все таки настораживает.

Еще замечательный пример с которым я столкнулся в практике.

Во время рефакторинга, значение метода в случае ошибки (false) было изменено на (null) проверку понятное дело я забыл сделать, а по дефолту метод возвращал объект известного типа. В итоге код вида


php > $x = $object->getResult();
php > $x->value = 'smth';
php > $x->callSmth();

Возвращал Fatal error: Call to undefined method stdClass::callSmth() in php ... некоторое время я тупил удивляясь откуда взялся stdClass, (и сразу пошел в неверном направлении, греша на serialize при работе с memcache), однако быстро понял что дело не в этом.

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

php > $a = null
php > ;
php > $a->x = 10;
php > var_dump($a);
object(stdClass)#1 (1) {
["x"]=>
int(10)
}


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


php > $b = 'sdf';
php > $b->x = 10;

Warning: Attempt to assign property of non-object in php shell code on line 1


Все страньше и страньше. Ну и на последок забавный код.


php > class null{};#я думал так нельзя
php > class false extends null{};# можно и так
php > class true extends false { function __toString() { return 'false'; } } ; #это уже понятно
php > $false = 'false';
php > $true = new True();
php > var_dump($$true);#ну это уже стеб.
string(5) "false"


Велики возможности PHP !!!

2 comments:

Dmitry Ivanov said...

Что касается сравнения массивов - ничего удивительного, сравниваются не только значения но и ключи. Видимо, дело в том что по своей природе все массивы в php ассоциативные, т.е. состоят из массива ключей и массива значений, соответственно и сравнение их требует сравнения обоих частей. В примере с числами массив значений отличается, а в примере с объектами нет, т.к. объекты сами по себе одинаковые.

Unknown said...

Да тут я погорячился. Нужно внимательнее читать доку. Я пропустил вот это :


При сравнении элементы массива считаются идентичными, если совпадает и ключ, и соответствующее значение.




Соотвественно при сравнении чисел все понятно, т.е. как вы и написали. С объектами тоже все правильно


При использовании оператора сравнения (==), свойства объектов просто сравниваются друг с другом, а именно: два объекта равны, если они содержат одинаковые свойства и одинаковые их значения и являются экземплярами одного и того же класса.



Тут я поторопился, потому что ожидал операцию сравнения объектов ===, которая бы показала что это действительно разные объекты.

 
Каталог сайтов, Добавить сайт