php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #72408 Coalescing operator on classes with overridden __get() method and NOT __isset()
Submitted: 2016-06-15 07:27 UTC Modified: 2016-06-15 12:29 UTC
From: kostasxx at gmail dot com Assigned:
Status: Not a bug Package: Scripting Engine problem
PHP Version: 7.0.7 OS: Linux 4.1.13
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: kostasxx at gmail dot com
New email:
PHP Version: OS:

 

 [2016-06-15 07:27 UTC] kostasxx at gmail dot com
Description:
------------
When __get() method is overridden in a class and NOT the __isset(), when the null coalescing operator is used, the __get() is triggered instead of native isset().

This issue is related to https://bugs.php.net/bug.php?id=71359

Test script:
---------------
https://3v4l.org/RMS3W


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2016-06-15 11:33 UTC] requinix@php.net
-Status: Open +Status: Feedback
 [2016-06-15 11:33 UTC] requinix@php.net
Why is the first test supposed to call __get but the second should not? Neither $attribute1 nor $attribute2 exist so the behavior should be the same for both.
 [2016-06-15 11:40 UTC] kostasxx at gmail dot com
-Status: Feedback +Status: Open
 [2016-06-15 11:40 UTC] kostasxx at gmail dot com
Based on RFC, the use of coalescing operator should be equal to isset() and is based to the given example:

// Fetches the request parameter user and results in 'nobody' if it doesn't exist
$username = $_GET['user'] ?? 'nobody';
// equivalent to: $username = isset($_GET['user']) ? $_GET['user'] : 'nobody';

taken from here https://wiki.php.net/rfc/isset_ternary.

So if you see in the updated code here https://3v4l.org/VUCFF, that isn't happening.
It bypass isset() and goes to __get() directly.
 [2016-06-15 11:50 UTC] requinix@php.net
-Status: Open +Status: Feedback
 [2016-06-15 11:50 UTC] requinix@php.net
Which it does for both tests. Your expected results are that it should say "value1" for the first test, thus invoking __get, but not try to do the same for the second. That's inconsistent.

So you mean to say that both of them should show "default", right? Neither of the tests should call __get because $attribute1 and 2 are not actually defined.

However,

Like I said in the other bug report, ($x??$y) is equivalent to (isset($x)?$x:$y).
So in this case
  var_dump($coal->attribute1 ?? 'default');
should be the same as
  var_dump(isset($coal->attribute1) ? $coal->attribute1 : 'default');
but without the second trip to ->attribute1.

Since your class did not implement __isset, doing "$coal->attribute1" will call __get. That's how it is supposed to work. Because the very existence of __get means that PHP should not look only at properties defined directly on the instance to determine values.

Make sense?
 [2016-06-15 11:56 UTC] kostasxx at gmail dot com
-Status: Feedback +Status: Closed
 [2016-06-15 11:56 UTC] kostasxx at gmail dot com
Now it makes sense. Since the parameter does not exist, the __get() is triggered.
Thanks for the explanation and sorry for the trouble :). 
I will mark the issue as closed.
 [2016-06-15 12:29 UTC] requinix@php.net
-Status: Closed +Status: Not a bug
 
PHP Copyright © 2001-2026 The PHP Group
All rights reserved.
Last updated: Tue Oct 06 21:00:01 2026 UTC