On 5/26/2016 12:03 AM, Stanislav Malyshev wrote: > Hi! > >> Andrea already said that we would not use it for untyped properties, >> hence, no BC. > > Again, it's not that simple. Properties are not local. That means any > code that can deal with a class that may have typed properties (which > may be library class, for example, so you don't even know what it has > inside) has to deal with the possibility of it being of the new type. So > if the old code uses is_null($object->foo) as means to check if the > value wasn't initialized, and it's no longer null, then that code is > broken and needs to be rewritten. That's a BC break. Yes, it will never > happen if you never use typed properties, and never use any libraries > that might use typed properties, but then what's the point of the whole > thing? The point of BC is that if you don't use new features, you don't > have to change your code and it will keep working. With the proposed > solution, it won't be the case. > >> It is not the same as null, very similar, but definitely not the same. >> Think of it in DB terms: >> >> | table | >> | ----- | >> | id | >> >> SELECT name FROM table; >> >> That's not null, it's not defined (undefined, unset, ...). In other >> words, null is a value and undefined/unset a state. > > "name" is not a value, as in if you do that in SQL, you don't get a > value, you get an error. Same as if you wrote "please can I haz a > pony?". It's just something the SQL can not give you, so it produces an > error. What is proposed here, however, is a PHP type, not an error. > That's a different thing - if you have a variable, then you have to have > a value, and if you have a value, then you have to have a type. >
I understand where you are getting at. Another proposal after giving this some more thought. var_dump($a); // null + E_NOTICE Undefined var_dump(isset($a)); // false var_dump(is_null($a)); // true + E_NOTICE Undefined var_dump($a == null); // true + E_NOTICE Undefined var_dump($a === null); // true + E_NOTICE Undefined $a = ['x' => null]; var_dump($a['x']); // null var_dump(isset($a['x']); // false var_dump(array_key_exists($a['x'])); // true var_dump(is_null($a['x']); // true var_dump($a['x'] == null); // true var_dump($a['x'] === null); // true $b = (object) []; var_dump($b->x); // null + E_NOTICE Undefined var_dump(isset($b->x)); // false var_dump(property_exists($b, 'x')); // false var_dump(is_null($b->x)); // true + E_NOTICE Undefined var_dump($b->x == null); // true + E_NOTICE Undefined var_dump($b->x === null); // true + E_NOTICE Undefined $c = new class { public int $x; }; var_dump($c->x); // null + E_NOTICE Uninitialized var_dump(isset($c->x)); // false var_dump(property_exists($c, 'x')); // true var_dump(is_null($c->x)); // true + E_NOTICE Uninitialized var_dump($c->x == null); // true + E_NOTICE Uninitialized var_dump($c->x === null); // true + E_NOTICE Uninitialized $d = new class { public ?int $x; }; var_dump($d->x); // null + E_NOTICE Uninitialized var_dump(isset($d->x)); // false var_dump(property_exists($d, 'x')); // true var_dump(is_null($d->x)); // true + E_NOTICE Uninitialized var_dump($d->x == null); // true + E_NOTICE Uninitialized var_dump($d->x === null); // true + E_NOTICE Uninitialized $e = new class { public ?int $x = null; }; var_dump($e->x); // null var_dump(isset($e->x)); // false var_dump(property_exists($e, 'x')); // true var_dump(is_null($e->x)); // true var_dump($e->x == null); // true var_dump($e->x === null); // true /* {{{ PHP 7.1 */ $f = new class { public $x; }; var_dump($f->x); // null var_dump(isset($f->x)); // true + E_STRICT Uninitialized var_dump(property_exists($f, 'x')); // true var_dump(is_null($f->x)); // true var_dump($f->x == null); // true var_dump($f->x === null); // true /* }}} */ /* {{{ PHP 8 */ $g = new class { public $x; }; var_dump($g->x); // null + E_NOTICE Uninitialized var_dump(isset($g->x)); // false var_dump(property_exists($g, 'x')); // true var_dump(is_null($g->x)); // true + E_NOTICE Uninitialized var_dump($g->x == null); // true + E_NOTICE Uninitialized var_dump($g->x === null); // true + E_NOTICE Uninitialized /* }}} */ The only thing I personally dislike is the fact that there is no counterpart to isset(). This means that one cannot create a positive conditional that checks for the opposite case without raising an E_NOTICE. class T { private int $x; public function getX() { if (isset($this-x) === false) { $this->x = 42; } return $this->x; } } However, one could argue that empty() is good enough at this point -- despite the fact that many values are considered empty that might be valid values in other circumstances -- because we want to know the uninitialized case here. From the manual: > The following things are considered to be empty: [...] a variable > declared, but without a value > > --- https://secure.php.net/function.empty class T { private int $x; public function getX() { if (empty($this->x)) { $this->x = 42; } return $this->x; } } I could live with that. Note that the behavior of isset() and empty() was already once changed during the 5.4 feature release! I am proposing to change it with a major version for existing code and only emitting an E_STRICT till then. This is not even close as brutal as that behavioral change back then but other than that pretty much the same change. This time it just affects objects and not associative arrays. -- Richard "Fleshgrinder" Fussenegger
signature.asc
Description: OpenPGP digital signature