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

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to