4

If i use magic __set to set a value to private var how could i set a var as an array ?

Im thinking of something like this, pretend i have a class with __get __set

$myclass->names = 'Name'; // Works
$myclass->names = array('n1'=>'Name1', 'n2' => 'Name2'); // works as well

//this does not work
$myclass->names['n1'] = 'Name1';
$myclass->names['n2'] = 'Name2';

Its the 2 last examples i want to get to work. Have tested various ways but cant figure it out.

1
  • Do you get an error or warning? Commented Mar 11, 2012 at 10:41

4 Answers 4

4

You obviously don't output notices, otherwise you'd have gotten the error

Notice: Indirect modification of overloaded property Foo::$bar has no effect

What you're trying to do is simply not possible. There is exactly one way to make arrays received through __get writable, but that is most likely not what you want.

<?php

class Foo {
    protected $bar = array();

    public function &__get($name) {
        return $this->$name;
    }

    public function __set($name, $value) {
        return $this->$name = $value;
    }
}

$foo = new Foo();
$foo->bar = array('a', 'b', 'c');
echo $foo->bar[0]; // output "a"
$foo->bar[0] = 'z'; // fires warning
echo $foo->bar[0]; // output "z"

// all fine, but here's the catch:
$t =& $foo->bar;
$t = array('y');
echo $foo->bar[0]; // output "y"

Now that you've seen how returning values by reference can be a problem, you may be interested in ArrayObject. Something like

<?php

class Foo {
    protected $bar = array();

    public function __get($name) {
        return new ArrayObject(&$this->$name);
    }

    public function __set($name, $value) {
        return $this->$name = $value;
    }
}

$foo = new Foo();
$foo->bar = array('a', 'b', 'c');
echo $foo->bar[0]; // output "a"
$foo->bar[0] = 'z'; // fires warning
echo $foo->bar[0]; // output "z"

// all fine, and no catch
$t =& $foo->bar;
$t = array('y');
echo $foo->bar[0]; // still outputs "z"
Sign up to request clarification or add additional context in comments.

1 Comment

Yes i got some error in output but since i worked with this last time on friday i had forgotten about it. Im instead using now public var which works as supposed
2

It won't work. $class->arr['key'] will execute the getter. So basically, what your code will look like is:

array('key' => 'value')['key'] = 'new value';

Which, obviously, does nothing. If you want that to work, you will have to declare the names as a public property.

1 Comment

While you're right about "it won't work", you're explanation of why is plain wrong.
2

This expression will invoke the getter:

 $myclass->names['n1'] = 'Name1';
 ^^^^^^^^^^^^^^^
 needs to be get
                ^^^^^^^^^^^^^^^^
                assignment later

The only way to make that work is a fugly workaround. By letting the getter return an reference to the know array the following assignment could work.

 function & __get($name) {

     if (is_array($this->$name)) {
          return & $this->$name;
     }
     else ...
 }

So it's really only advisable if it significantly simplifies your API.

Comments

0

Try this code:

class Foo
{
    private $bar;

    public function __construct()
    {
        $this->bar = new ArrayObject(array());
    }

    public function __get($item)
    {
        if(property_exists($this, $item)) {
            return $this->$item;
        }
    }

    public function __set($item, $value)
    {
        if(property_exists($this, $item)) {
            $this->{$item} = $value;
        }
    }
}

$obj = new Foo();
$obj->bar['color'] = 'green';
foreach($obj->bar as $attribute => $value) {
    echo '<p>' . $attribute . ' : ' . $value . '</p>' . PHP_EOL;
}
// output => color : green

3 Comments

The class declares bar privately, yet the calling code access' it as if it was public. This will not work.
Of course this will work because of public magic getter/setter methods. In fact, when you say echo $obj->bar; the __get method with be called with 'bar' parameter sent to it and when you say $obj->bar = 5; the setter is called with 'bar' and 5 parameters. Read more about magic methods.
I don't remember writing that comment... but I clearly didn't read your code properly. You are, of course, correct.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.