Req #69659 [Asn->Csd]: ArrayAccess, isset() and the offsetExists method
| From: | nikic@php.net | Date: | Sun, 20 Mar 2016 17:21:45 +0000 |
| Subject: | Req #69659 [Asn->Csd]: ArrayAccess, isset() and the offsetExists method | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-199967@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=69659&edit=1
ID: 69659
Updated by: nikic@php.net
Reported by: contact dot 01834e2c at renegade334 dot me dot uk
Summary: ArrayAccess, isset() and the offsetExists method
-Status: Assigned
+Status: Closed
Type: Feature/Change Request
Package: SPL related
Operating System: Ubuntu 14.04.2 (Linux 3.13.0-52)
PHP Version: master-Git-2015-05-19 (Git)
Assigned To: nikic
Block user comment: N
Private report: N
New Comment:
ArrayObject part handled by http://git.php.net/?p=php-src.git;a=blobdiff;f=ext/spl/spl_array.c;h=d5cb32606ea4cb4843548ed2f50dbbb3c174976c;hp=685dd27092acb70f3613aa6458162916d9a6f6ca;hb=f3309173f916e3c5cf37910975f04310706336b5;hpb=12f2665df829eac53e2036e335b40cf391ff8652.
Previous Comments:
------------------------------------------------------------------------
[2016-03-20 12:56:57] nikic@php.net
Mostly fixed by https://github.com/php/php-src/commit/a175aa9dcaed5e295d015ff73c663e06c2335155.
ArrayObject may need additional modifications.
------------------------------------------------------------------------
[2015-05-19 07:48:02] contact dot 01834e2c at renegade334 dot me dot uk
Description:
------------
Calling isset() or empty() on a dimension of an object that implements ArrayAccess results in the
offsetExists method being called.
When calling isset() or empty() on a subdimension of a dimension of that object, only the offsetGet
method is called, not the offsetExists method. This is inconsistent, undocumented, and often results
in undefined index notices being raised.
Instead, when isset() or empty() is called on a subdimension of an object implementing ArrayAccess,
the offsetExists method should first be called to check if the dimension exists. If the dimension
does not exist, then offsetGet should not be called.
This could possibly be implemented at the level of zend_std_read_dimension() by calling and checking
the "offsetexists" method if type==BP_VAR_IS.
This was previously raised several years ago as #41727. At the time, it was deemed WONTFIX, although
the discussion seemed to miss the point somewhat. I think the issue should be revisited, not least
because the lack of consistency leads to some interesting quirks elsewhere.
For example, SPL's ArrayObject class, which 'implements' ArrayAccess internally, will
also not call offsetExists when executing isset($obj['foo']['bar']). However,
while the native "get dimension" handler detects the BP_VAR_IS type and will not throw an
invalid index error in this case, calling parent::offsetGet() from an overridden offsetGet method
*will* result in invalid index errors being thrown. This was reported under #62059.
Test script:
---------------
https://gist.github.com/Renegade334/2415ec56367ff937c407
Expected result:
----------------
renegade@ochre:~$ builds/php7/bin/php test.php
* Calling isset($obj['foo'])...
offsetExists('foo')
bool(false)
* Calling isset($obj['foo']['bar'])...
offsetExists('foo')
bool(false)
* Setting offset...
offsetSet('foo', NULL)
* Calling isset($obj['foo']['bar'])...
offsetExists('foo')
offsetGet('foo')
bool(false)
Actual result:
--------------
renegade@ochre:~$ builds/php7/bin/php test.php
* Calling isset($obj['foo'])...
offsetExists('foo')
bool(false)
* Calling isset($obj['foo']['bar'])...
offsetGet('foo')
Notice: Undefined index: foo in /home/renegade/test.php on line 14
bool(false)
* Setting offset...
offsetSet('foo', NULL)
* Calling isset($obj['foo']['bar'])...
offsetGet('foo')
bool(false)
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=69659&edit=1