php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #41727 ArrayAccess::offsetExists works wrong with isset()
Submitted: 2007-06-18 13:00 UTC Modified: 2011-09-28 23:51 UTC
Votes:10
Avg. Score:4.6 ± 0.7
Reproduced:7 of 8 (87.5%)
Same Version:3 (42.9%)
Same OS:3 (42.9%)
From: dan at yes dot lt Assigned:
Status: Wont fix Package: SPL related
PHP Version: 5.2.3 OS: WinXP
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: dan at yes dot lt
New email:
PHP Version: OS:

 

 [2007-06-18 13:00 UTC] dan at yes dot lt
Description:
------------
method ArrayAccess actualy works wrong with isset()/empty()...

isset()/empty() now calls only ArrayAccess::offsetExist, but should call both ArrayAccess::offsetExist and ArrayAccess::offsetGet to check if value is realy set.

that's how arrays do...

Reproduce code:
---------------
class Test implements ArrayAccess
{
  protected $_array = array();
  protected $_count = 0;

  function offsetExists($offset)
  {
    return $offset >= 0 && $offset < $this->_count;
  }
  function offsetGet($offset)
  {
    return $this->_array[$offset];
  }
  function offsetSet($offset, $value)
  {
    $this->_array[] = $value;
    $this->_count++;
  }
  function offsetUnset($offset)
  {
    unset($this->_array[$offset]);
  }
}

$a = new Test;
$a[] = 'A';  // 0
$a[] = 10;   // 1
$a[] = null; // 2

echo isset($a[0]) ? 'set' : 'unset', "\n";
echo isset($a[1]) ? 'set' : 'unset', "\n";
echo isset($a[2]) ? 'set' : 'unset', "\n";

Expected result:
----------------
set
set
unset

Actual result:
--------------
set
set
set

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2007-06-21 21:55 UTC] johannes@php.net
Thank you for taking the time to write to us, but this is not
a bug. Please double-check the documentation available at
http://www.php.net/manual/ and the instructions on how to report
a bug at http://bugs.php.net/how-to-report.php

You can call offsetGet() yourself if you want.
 [2007-06-22 04:38 UTC] dan at yes dot lt
isset ? Determine whether a variable is set
[http://php.net/isset]

array_key_exists ? Checks if the given key or index exists in the array
[http://php.net/array-key-exists]

<?php
$a = array(0 => 10, 1 => null);
// so...
var_dump(isset($a[0]));             // bool(true)
var_dump(array_key_exists(0, $a));  // bool(true)
// but...
var_dump(isset($a[1]));             // bool(false)
var_dump(array_key_exists(0, $a));  // bool(true)
?>

now... 

ArrayObject::offsetExists ? Returns whether the requested $index exists
[http://php.net/ArrayObject-offsetExists]

so, offsetExists must return the same as array_key_exists... but how isset() must work with ArrayAccess?..

<?php
$a = new ArrayObject(array(0 => 10, 1 => null));
// so...
var_dump(isset($a[0]));             // bool(true)
var_dump($a->offsetExists(0));      // bool(true)
var_dump(array_key_exists(0, $a));  // bool(true)
// but...
var_dump(isset($a[1]));             // bool(true) | false expected
var_dump($a->offsetExists(1));      // bool(true)
var_dump(array_key_exists(1, $a));  // bool(true)
?>

in this case isset() returns true, but obviously must return false... don't you think so?.. isn't this situation silly?..
and do you still think - "this is not a bug"?..
 [2007-06-22 07:34 UTC] johannes@php.net
Yes, I still think so.
 [2007-06-22 07:46 UTC] dan at yes dot lt
ok, now think... if you have method to work with array or any object with ArrayAccess implemented...

function some($list)
{
    if (isset($list[0])) {
       // do something with $list[0]
       return true;
    } else {
       // no $list[0] defined, skipping
       return false;
    }
}

user, who implements this function must not know the real type of the $list variable - but only that this variable can be accessed as array...

now - if $list = array(0 => null), then this function works correctly, but if $list = new ArrayObject(array(0 => null)), then it fails...

now, you say, i must to use offsetGet method... then, i must check whether $list is instance of ArrayAccess, then add complex checkings using offsetExists and offsetGet... was the ArrayAccess realy planned to be such a silly structure to use it in such complex way?.. I don't think so. I still think, isset() must automaticaly call offsetGet after offsetExists returns true...
 [2007-06-22 10:29 UTC] johannes@php.net
.
 [2007-06-22 10:35 UTC] dan at yes dot lt
I see... you make php for yourself, but not for others... you don't listen for arguments, just skipping the bugs... without any reason explanations...

thank you for good support and correct php!
 [2011-09-28 17:48 UTC] stas@php.net
What prevents you from implementing offsetExists with any checks you like, 
including null check?
 [2011-09-28 23:51 UTC] colder@php.net
-Status: Bogus +Status: Wont fix
 [2011-09-28 23:51 UTC] colder@php.net
This is a known "problem", on one hand offsetExists is similar to 
array_key_exists, on the other hand, it is the only thing called by isset.

Even though this is a bit of a problem, I don't believe it is worth modifying 
the isset() behavior now to call get, as that would be some BC break that would 
not be easy to track down.

I guess the only thin gto do now is accept that offsetExists mimics isset(), 
that nothing mimics array_key_exists, and work with that, making this a Won't 
fix.
 [2017-12-06 13:09 UTC] a dot ryazanov at superjob dot ru
The behavior is still here with 7.1.12, and I still suppose it's a bug. Since the docs (https://secure.php.net/manual/en/function.isset.php) clearly tells "isset — Determine if a variable is set and is not NULL", it should work as documented, but it doesn't: it doesn't check if the value of ArrayAccess element is not null.

Also, as mentioned above, it breaks ArrayAccess compatibility with natural arrays, thus making this interface virtually useless: if you can't mimic an array with the object and have to check what is the type of array-like variable before interacting with it, then implementing ArrayAccess/ArrayObject etc makes no sense,
 [2021-04-08 12:22 UTC] php at example dot com
This is embarrassing... Bug #61347 was fixed (in PHP 5.3.11 / 5.4.1) but only for the ArrayObject implementation, not the ArrayAccess interface :/
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Dec 21 17:01:58 2024 UTC