php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #75831 Coalesce operator ?? never uses the default isset() handler
Submitted: 2018-01-17 11:44 UTC Modified: 2019-01-25 16:24 UTC
Votes:2
Avg. Score:3.0 ± 2.0
Reproduced:2 of 2 (100.0%)
Same Version:1 (50.0%)
Same OS:1 (50.0%)
From: nobots dot nospam at example dot org Assigned: nikic (profile)
Status: Assigned Package: *General Issues
PHP Version: 7.2.1 OS:
Private report: No CVE-ID: None
 [2018-01-17 11:44 UTC] nobots dot nospam at example dot org
Description:
------------
The coalesce operator calls __get(prop) directly without testing isset($obj->prop) first.

It only calls isset($obj->prop) if there is an explicit user-defined __isset() handler.

Test script:
---------------
class Bar{
    function __get($a){
        throw new Error("no prop error\n");
    }
}

$bar = new Bar;

try{
    var_dump($bar->foo ?? "qux"); // error...
} catch(Throwable $e){ echo $e->getMessage(); }

var_dump(isset($bar->foo)); // ...but this works fine

Expected result:
----------------
class Bar{
    function __isset($a){
        return isset($this->{$a});
        // I shouldn't be forced to implement this,
        // since it looks exactly like the default isset() handler
    }
    function __get($a){
        throw new Error("no prop error\n");
    }
}

$bar = new Bar;
var_dump($bar->foo ?? "qux"); // works now, without errors...


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2018-01-21 17:23 UTC] timok at ya dot ru
Imho, this is not a bug, but quite expected and correct behavior.

You define a handler to get inaccessible properties (__get), then it is called whenever you try to access an inaccessible property, including NULL coalesce operator. If object has a property check method (__isset), then it is called before __get. So, the code

  var_dump($bar->foo ?? "qux"); // works now, without errors...

- is equivalent to the following:

  var_dump(isset($bar->foo) ? $bar->foo : "qux"); // also works without errors: https://3v4l.org/4EPXm

- http://php.net/manual/en/language.operators.comparison.php#language.operators.comparison.coalesce
- https://wiki.php.net/rfc/isset_ternary
 [2019-01-25 16:24 UTC] nikic@php.net
-Status: Open +Status: Assigned -Assigned To: +Assigned To: nikic
 [2019-01-25 16:24 UTC] nikic@php.net
I agree with the original reporter that this is a bug. $foo->bar ?? $baz should behave the same way as isset($foo->bar) ? $foo->bar : $baz, and in this case it does not.

https://3v4l.org/UI13h
 [2020-04-23 09:21 UTC] michael dot vorisek at email dot cz
Is this expected to be fixed soon - and backported or at least in PHP 8.0?
 [2020-11-18 07:02 UTC] jakechapa at gmail dot com
I found the following behavior odd. Is it expected as ewll?

```
class MagicProp 
{
  public function __isset($key)
  {
	return false;
  }
  
  public function __get($prop) {
  	return 'yes';
  }
}   

$magic = new MagicProp();

return $magic->prop;       // returns 'yes'
return $magic->prop ?? 1;  // returns 1

```
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Dec 12 04:01:27 2024 UTC