php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #34783 Contradictory errors using ArrayAccess
Submitted: 2005-10-07 18:33 UTC Modified: 2005-10-07 23:09 UTC
From: oliver dot graetz at gmx dot de Assigned:
Status: Not a bug Package: SPL related
PHP Version: 5.1.0RC1 OS: WinXP, Debian Linux
Private report: No CVE-ID: None
View Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
If you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: oliver dot graetz at gmx dot de
New email:
PHP Version: OS:

 

 [2005-10-07 18:33 UTC] oliver dot graetz at gmx dot de
Description:
------------
I wrote a class implementing ArrayAccess that should behave like a normal array to the outside world. So If I used an element in this array it should be usable like any other array. But there was a problem if the "array" elements were arrays themselves. I got this error:

Fatal error: Objects used as arrays in post/pre increment/decrement must return values by reference in t.php on line 123

OK, you want a reference, you get it. I changed offsetGet to &offsetGet. This worked fine with PHP5.0. But in PHP5.1 the parser became more picky about this:

Fatal error: Declaration of WAF_Config::offsetGet() must be compatible with that of ArrayAccess::offsetGet() in myclass.php on line 234

This is correct but it makes implementing ArrayAccess in a way consistent with ordinary arrays impossible!


Reproduce code:
---------------
<?php
class test implements ArrayAccess
{
    private $data=array();

    function offsetSet($key,$value) { $this->data[$key] = $value; }
//    function &offsetGet($key) { return $this->data[$key]; }
    function offsetGet($key) { return $this->data[$key]; }
    function offsetUnset($key)
    {
        if (array_key_exists($key,$this->data)) { unset($this->data[$key]); }
    }
function offsetExists($key) { return array_key_exists($key,$this->data); }
}

$t=new test();
$t['huba']=array('one','two');
$t['huba'][]='three';
print_r($t['huba']);


Expected result:
----------------
Array ( [0] => one [1] => two [2] => three ) 


Actual result:
--------------
using offsetGet
Fatal error: Objects used as arrays in post/pre increment/decrement must return values by reference in t.php on line 17

using &offsetGet
Fatal error: Declaration of test::offsetGet() must be compatible with that of ArrayAccess::offsetGet() in t.php on line 2


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2005-10-07 19:07 UTC] oliver dot graetz at gmx dot de
Sorry, I thought I checked everything but I found something similar to this bug here as a comment:

http://bugs.php.net/bug.php?id=32983

Still, I think that
"We found out that this is not solvable without blowing up the interface and creating a BC or providing an additional interface to support references and thereby creating an internal nightmare - actually i don't see a way we can make that work ever."
is not an acceptable answer. Using &offsetGet worked fine in 5.0. An, as I found out, this works in PHP5.0 without &offsetGet:

$entry=&$test->offsetGet('valid_op');
$entry[]='three';

So, PHP5.1 didn't fix the interface parser but instead introduced a BC break.
 [2005-10-07 19:14 UTC] oliver dot graetz at gmx dot de
One more point: Adding the & outside of the class just allows referencing under PHP5.0 but not under 5.1. But having references is in no way unfixable under 5.1:

class test
{
// rest as before
function &offsetGetRef($key) { return $this->data[$key]; }
}

$t=new test();
$t['huba']=array('one','two');
$entry=&$t->offsetGetRef('huba');
$entry[]='three';
print_r($t['huba']);

Voil?! It works. Telling that it's unfixable just doesn't do the issue justice. Perhaps the fix is more difficult but it can be done. And "we didn't mean to support references in the first place" isn't valid since normal arrays are meant to be used this way and ArrayAccess was meant to mimic this for objects.
 [2005-10-07 20:20 UTC] helly@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

Just to state this again: IT IS IMPOSSIBLE TO HAVE ARRAYACCESS DEAL WITH REFERENCES.

If you don\'t like that statement i suggest you prove it wrong by writing a patch that actually works in all cases.
 [2005-10-07 21:41 UTC] oliver dot graetz at gmx dot de
Won't happen. I'm just a user of PHP. As a result, this is one more case where using a new feature becomes impossible by breaking BC (between 5.0 and 5.1). A yound and promising feature has to be left behind, ArrayAccess won't be in use any more in future projects by certain people since the desired behaviour can easily be achieved by using ordinary methods. Syntactic sugar going to hell.
 [2005-10-07 22:40 UTC] oliver dot graetz at gmx dot de
Why did this work in 5.0.3 by using &offsetGet() and can't be made to work in 5.1? Why would changing the interface to read &offsetGet break anything other than the (up to now) few apps DEFINING it without the ampersand? 5.0 didn't complain about this at all and it worked. The issues caused by a simple change of the interface a far inferior to those caused by the "only variables can be passed by reference" some weeks ago. And you're avoiding more serious trouble in later versions when more and more applications are relying on the false behaviour?
 [2005-10-07 23:09 UTC] oliver dot graetz at gmx dot de
Perhaps there shouldn't be afix for the reference issues since they are not meant to happen looking at the interface. But $data['element']['element2']="hi"; should definitely work! Perhaps a fix to look if the first part of this code is accessing an object instead of a real array has to be applied. An ordinary user sees nothing of a reference. Either fix this with ArrayAccess or completely yank the interface! 

I see a future where more and more framework code is pretending to be an array. If then users get this error message they won't understand the world. "It's an array!? Where's the reference? Why the *#?* isn't this working? I hate PHP5!"

If you implement code so something can look like an array than it MUST be able to truely behave like an array.
 [2010-08-03 16:27 UTC] georgwaechter at googlemail dot com
Hi Oliver,

in my opinion you are absolutely right! I'm struggling with this "bug" for months now. The interface ArrayAccess is actually really useless until some serious php developers undestand that its essential that ArrayAccess objects behave like normal arrays. For modern object oriented programming this is simply a must. Enhanced this means that all array related functions work with those objects too.

The current implementation is not complete.

Greets

Georg
 [2011-05-26 03:43 UTC] tohru at reedom dot com
It's a bug since the current behavior breaks the Liskov's Substitution Principle
when a subclass just overrides offsetGet().
http://www.oodesign.com/liskov-s-substitution-principle.html
 [2013-04-16 04:59 UTC] me at achronos dot ca
Although no php dev has ever mentioned it in a bug report (that I can find), this issue has in fact been fixed.
At least, it has been fixed for ArrayAccess.
(For ArrayObject, I haven't tested.)

According to the PHP docs (http://php.net/manual/en/arrayaccess.offsetget.php notes section)
this was fixed in 5.3.4 by relaxing the requirements for implementing AccessAccess, so that
 public function &offsetGet($offset) {}
works, and thus indirect access works.

I've confirmed this does in fact work (on 5.3.8).

There are multiple bug reports all related to this topic:
 https://bugs.php.net/bug.php?id=51622
 https://bugs.php.net/bug.php?id=34783
 https://bugs.php.net/bug.php?id=32983
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sat Dec 21 14:01:32 2024 UTC