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
 [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: Sun Dec 08 12:01:28 2024 UTC