Monday, October 27, 2008

Как я люблю php, или танцы с false

Еще одна из кривостей моего любимого php. Писать не буду, приведу пример интерактивного шела.
Cюрприз #2

pcd@cd-laptop:~$ php -a
php > error_reporting(E_ALL);// устанавливаем уровень ошибок,

php > $ar = array(); // создаем массив
php > var_dump($ar[1]); // обращаемся к несуществующему индексу
Notice: Undefined offset: 1 in php shell code on line 1//логично
NULL

php > $null = null;// создаем переменну инициализированную нулом
php > var_dump($null[1]);// обращаемся к нему как к массиву
NULL// ошибки нет, это уже не совсем логично, т.к.

php > var_dump( (array) $null ) ; // при преобразовании нула в массив
array(0) {
}// получается пустой массив без индекса 1.
//ну хотя можно как то объяснить, т.к. null это особый тип.

php > $false = false;// boolean переменная, инициализированная ложью
php > var_dump($false[1]);// обращение как к массиву при этом к несуществующиему индексу
NULL// а как объяснить это????

php > var_dump((array)$false);// смотрим как ложь приводится к массиву.
array(1) {
[0]=>
bool(false)
}// этого я не ожидал
// но тогда получается что ...

php > echo (array) false ? 'true' : 'false';
true // ну а это просто п***ц, сколько человек могло попасть так!


Ну и навскидку надуманный пример, похожий на правду.



cd@cd-laptop:~$ cat ex1.php
class ExampleDb
{

/**
* This function return list of users as array,
* empty array on failure
*/
public function findAll($testValue = true)
{
return (array ) $this->_fetch_all($testValue);
}
protected function _fetch_all($testValue = true )
{
$goodData = array(
0 => array(
'name' => 'vasya',
'pass' => 'oyamd5withsolt',
),
1 => array(
'name' => 'vasay',
'pass' => 'oyamd5withsolt2',
),
);
try
{
;//do smth
}
catch (Exception $e)
{
return false; //strange architector
}

$retValue = $testValue ? $goodData : false;
var_dump($retValue);
return $retValue;

}
}

$ob = new ExampleDb();
$users = $ob->findAll(false);// error happens !

//strange dev
if ( isset($users[0]) )
echo "You win! Your prize 10000k euros from dev salary!";


?>
cd@cd-laptop:~$ php ex1.php
(bool)false // мы видим что была ошибка
You win! Your prize 10000k euros from dev salary!cd@cd-laptop:~$
// но тем не менее кто то выйграл.
//Ну что теперь 10 лет работаем на еду?

4 comments:

Станислав said...

Знатный косяк. Хотя явное приведение к массиву достаточно извращенное желание.

Баг-репорт засабмичен?

cd said...

1. Это не баг, это вроде задокументированная вещь :)

Порылся в php.net


Преобразование в массив
Для любого из типов: integer, float, string, boolean и resource, если вы преобразуете значение в массив, вы получите массив с одним элементом (с индексом 0), являющимся скалярным значением, с которого вы начали.


Просто по моему мнению, в php слишком много вещей которые нужно знать, а у меня память плохая :) Поэтому я узнав язык пытаюсь пользоваться "ожидаемыми" вещами, разумеется проверяя их.


А вот прикол с явным приведением к массиву вылез у нас в проекте :)

Bruce Weirdan said...

классическая проблема с scalar -> array выглядит примерно так:

function getSomeArray() {
if (something) {
return array(1,2,3);
} else {
return null;
}
}

//...
if (count($arr = getSomeArray())) {
echo 'non-empty array' . var_export($arr, true);
}

cd said...

Не спорю, это все правильно.

Однако что делать с

php > var_dump( count(false) ) ;
int(1)
php > var_dump( count(null) ) ;
int(0)
php > var_dump( count(array() ) ) ;
int(0)


Суть в следующем, очень часто функция в качестве ошибки возвращает именно false. Правильнее конечно проверять возвращаемое значение как

if ( false !== funcGetArray() )
{
// do smth
}

Однако про это часто забывается, а в приведенном примере

if ( count ( $ar = functGetArray() ) )
// do ok
else
// do error

Если функция вернет false, то мы все равно в луже.

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