Array property of object with __get and __set - is this a bug?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Jon Maz

    Array property of object with __get and __set - is this a bug?

    Hi All,

    I'm reasonably proficient with C#, and am starting with php5. I was happy
    to learn of the __get and __set methods, but am encountering a problem using
    them to set an object property of type "array".

    Below is a simple example of the problem I'm having with a sample object
    "Article", which has an array property "authors". As you can see, I can't
    even use standard php array syntax to set a single author, even though the
    same syntax outside of the object works perfectly.

    Am I doing something wrong here, or is this a php5 bug?

    TIA,

    JON

    ---------------------------------------


    //test with normal array
    $array = array();
    $array[] = "Mr Jones";
    print $array[0] . "<br>";

    // expected result: "Mr Jones"
    // actual result: "Mr Jones"

    //test with array property
    $article = new Article();
    $article->title = "my title";
    $article->authors[] = "Mr Smith";
    print $article->authors[0] . "<br>";

    // expected result: "Mr Smith"
    // actual result: "Notice: Undefined offset: 0"

    //diagnosis: authors array is *not* being filled.
    // var_dump($artic le->authors);
    // gives
    // result: array(0) { }



    class Article
    {
    protected $properties = array(
    'title' => "",
    'authors' => array()
    );

    public function __construct()
    {
    }

    public function __get($property )
    {
    if( array_key_exist s($property, $this->properties) )
    {
    return $this->properties[$property];
    }
    else
    {
    throw new Exception();
    }
    }

    public function __set($property , $value)
    {
    if( array_key_exist s($property, $this->properties) )
    {
    $this->properties[$property] = $value;
    }
    else
    {
    throw new Exception();
    }
    }
    }



  • ZeldorBlat

    #2
    Re: Array property of object with __get and __set - is this a bug?

    Not really a bug..more a difference in the way __get and __set are
    handled. Remember that when you use these, something like:

    $x = $obj->y

    does something slightly different than what you expect. Consider the
    following:

    function makeArray() {
    $r = array(1, 2, 3, 4);
    return $r;
    }

    Could you then write something like this:

    echo makeArray()[2];

    No, because makeArray is a function, not a reference or variable. The
    same thing happens when you use __get() and __set(). Although it looks
    like regular property accessing and setting, it really isn't.

    This is the same reason you can't use overloaded __get() and __set with
    empty(), unset(), etc. (well, now you can overload those, too).

    The simplest solution to your problem is to pull out the array before
    you try and access or set it's element:

    $article = new Article();
    $article->title = "my title";
    $authors = array("Mr. Smith");
    $article->authors = $authors;
    print $authors[0] . "<br>";

    Comment

    • Oli Filth

      #3
      Re: Array property of object with __get and __set - is this a bug?

      ZeldorBlat said the following on 07/11/2005 14:34:[color=blue]
      > Not really a bug..more a difference in the way __get and __set are
      > handled. Remember that when you use these, something like:
      >
      > $x = $obj->y
      >
      > does something slightly different than what you expect. Consider the
      > following:
      >
      > function makeArray() {
      > $r = array(1, 2, 3, 4);
      > return $r;
      > }
      >
      > Could you then write something like this:
      >
      > echo makeArray()[2];
      >
      > No, because makeArray is a function, not a reference or variable.[/color]

      Actually, this is a limitation of PHP. In C, C++, C# and Java, the
      equivalent of the above code works fine.



      --
      Oli

      Comment

      • Wayne

        #4
        Re: Array property of object with __get and __set - is this a bug?

        On 7 Nov 2005 06:34:47 -0800, "ZeldorBlat " <zeldorblat@gma il.com>
        wrote:
        [color=blue]
        >No, because makeArray is a function, not a reference or variable. The
        >same thing happens when you use __get() and __set(). Although it looks
        >like regular property accessing and setting, it really isn't.[/color]

        Well you're right that you can't do someFunction()[0] but array access
        syntax does work for __get and _set. Try this in PHP5 and you'll get
        the desired result:

        class Test
        {
        public function __get($name) {
        return Array('hello', 'world');
        }
        public function blah()
        {
        return Array('hello', 'world');
        }
        }

        $test = new Test();
        echo $test->whatever[0];
        // displays 'hello'

        The original posters problem is entirely different.

        Comment

        • Wayne

          #5
          Re: Array property of object with __get and __set - is this a bug?

          On Mon, 7 Nov 2005 10:48:57 -0000, "Jon Maz"
          <jonmaz@surfeu. no.spam.de> wrote:
          [color=blue]
          >Hi All,
          >
          >I'm reasonably proficient with C#, and am starting with php5. I was happy
          >to learn of the __get and __set methods, but am encountering a problem using
          >them to set an object property of type "array".
          >
          >Below is a simple example of the problem I'm having with a sample object
          >"Article", which has an array property "authors". As you can see, I can't
          >even use standard php array syntax to set a single author, even though the
          >same syntax outside of the object works perfectly.
          >
          >Am I doing something wrong here, or is this a php5 bug?[/color]

          The problem is that arrays are values in PHP. So when you return an
          array from a function (or assign it to variable) you're really
          returing/assigning a copy of the array.
          [color=blue]
          >//test with array property
          >$article = new Article();
          >$article->title = "my title";
          >$article->authors[] = "Mr Smith";[/color]

          This line adds "Mr Smith" to a copy of the authors array (as returned
          by the __get function) and not the original array.

          Your best bet is to use an ArrayObject rather than an array. It works
          just like an array but, like all objects in PHP5, it's passed by
          reference and should work as you expect.

          Later,

          Comment

          • news.freeserve.com

            #6
            Re: Array property of object with __get and __set - is this a bug?

            Hi All,

            Thanks for the responses, they've helped me understand what's going on.

            -------------

            I think Oli hit the nail on the head when he wrote:
            [color=blue][color=green]
            > > Could you then write something like this:
            > > echo makeArray()[2];
            > > No, because makeArray is a function, not a reference or variable.[/color][/color]
            [color=blue]
            > Actually, this is a limitation of PHP. In C, C++, C# and Java, the
            > equivalent of the above code works fine.[/color]

            I was indeed expecting PHP to work just like C#. Does anybody know if
            there are plans to change this PHP behavior? Is this regarded as a bug
            or a feature? (My vote is for bug).

            -------------

            In the end I have decided to solve the problem by replacing my properties
            of type array() with properties of type CollectionBase, as found
            here: http://coding.mu/archives/2003/08/09...lection-class/. I think
            this is the solution Wayne was suggesting when he proposed using an
            object instead of an array.

            I decided to switch to this Collection object before Wayne gave the
            ArrayObject tip. I'd never heard of ArrayObject, but have found some
            useful info on it. Urls here in case they help anyone else:



            PHP is a popular general-purpose scripting language that powers everything from your blog to the most popular websites in the world.

            Founded in 1997, DEVShed is the perfect place for web developers to learn, share their work, and build upon the ideas of others.


            -------------

            Finally, in my digging around on the net I found the following. I don't
            100% follow the argument here, but it sounds like this guy is discussing
            the same issue I came across (true?).

            http://uk.php.net/manual/en/language...verloading.php[color=blue]
            > A few things I've found about __get()...
            >
            > First off, if you use $obj-> getOne-> getAnother, both intended
            > to be resolved by __get, the __get() function only sees the first
            > one at first. You can't access the second one. You can, however,
            > return the pointer to an object that can handle the second one.
            > In short, you can have the same class handle both by returning a
            > new object with the data changed however you see fit.
            >
            > Secondly, when using arrays like: $obj-> getArray["one"], only
            > the array name is passed on to __get. However, when you return
            > the array, PHP treats it just as it should. THat is, you'd have
            > to make an array with the index of "one" in __get in order to see
            > any results. You can also have other indexes in there as well.
            >
            > Also, for those of you like me, I've already tried to use
            > func_get_args to see if you can get more than just that one.
            >
            > If you're like me and were hoping you could pass some sort of
            > argument onto __get in order to help gather the correct data,
            > you're out of look. I do recommend using __call though. You could
            > easily rig __call up to react to certain things, like: $account->
            > properties( "type" ); , which is my example. I'm using DOM for
            > data storage (for now), and I'm trying to make an interface
            > that'll let me easily switch to something else - MySQL, flat
            > file, anything. This would work great though![/color]

            -------------

            Thanks once again for all the help,

            JON


            Comment

            Working...