PHP геттеры и сеттеры с массивом - PullRequest
1 голос
/ 11 марта 2012

Если я использую магию __set для установки значения в приватную переменную, как я могу установить переменную как массив?

Я думаю о чем-то подобном, представь, что у меня есть класс с __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';

Это 2 последних примера, которые я хочу получить. Опробовал разные способы, но не могу понять.

Ответы [ 4 ]

2 голосов
/ 11 марта 2012

Это не сработает. $class->arr['key'] выполнит получатель. В общем, ваш код будет выглядеть так:

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

Что, очевидно, ничего не делает. Если вы хотите, чтобы это работало, вы должны будете объявить names как публичную собственность.

1 голос
/ 11 марта 2012

Вы явно не выводите уведомления, иначе вы получили бы ошибку

Примечание: косвенное изменение перегруженного свойства Foo :: $ bar не имеет эффект

То, что вы пытаетесь сделать, просто невозможно. Существует только один способ сделать массивы, полученные с помощью __get доступными для записи, но, скорее всего, это не то, что вам нужно.

<?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"

Теперь, когда вы увидели, что возвращение значений по ссылке может быть проблемой, вас может заинтересовать ArrayObject . Что-то вроде

<?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"
1 голос
/ 11 марта 2012

Это выражение вызовет получатель:

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

Единственный способ заставить эту работу - безрассудный обходной путь. Позволяя получателю вернуть ссылку на массив данных, следующее назначение может сработать.

 function & __get($name) {

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

Так что это действительно целесообразно, только если значительно упрощает ваш API.

0 голосов
/ 11 апреля 2015

Попробуйте этот код:

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
...