Переменная PHP __set, а __get передается по ссылке - PullRequest
0 голосов
/ 24 февраля 2012

Я думаю, это довольно простой вопрос, но я не уверен.

У меня есть класс:

<?PHP
class PropertyTest {
    private $data = array();

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

    public function __get($name) {
        if (array_key_exists($name, $this->data)) {
            return $this->data[$name];
        }

        $trace = debug_backtrace();
        trigger_error(
            'Undefined property via __get(): ' . $name .
                ' in ' . $trace[0]['file'] .
                ' on line ' . $trace[0]['line'],
            E_USER_NOTICE);
        return null;
    }

    public function __isset($name) {
        echo "Is '$name' set?\n";
        return isset($this->data[$name]);
    }

    public function __unset($name) {
        echo "Unsetting '$name'\n";
        unset($this->data[$name]);
    }

    public function getHidden() {
        return $this->hidden;
    }
}
?>

Не знаю, почему, но блок 'code' в любом случае раздражает, как ад.

Просто базовая магия действительно установлена.Но когда я изменяю __get на передачу по ссылке, я больше не могу это делать:

$object->$variableName = $variableValue;

Я не уверен почему, хотя я предполагаю, потому что он проверяет, существует ли он, но так как он должен что-то вернутьссылаться на это не удастся, если его не существует с самого начала.Функция set не будет вызвана, вероятно, и даже если я верну ложное значение, она никогда не вызовет функцию set, потому что она «уже существует / имеет значение».

Правильно ли я понимаю?Если так, есть ли обход?Если нет, то как это работает и есть ли обходной путь?

1 Ответ

0 голосов
/ 24 февраля 2012

Если я что-то упускаю, у меня все работает нормально

<?php
class PropertyTest
{

    private $data = array();

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

    public function &__get($name)
    {
        if(array_key_exists($name, $this->data))
            return $this->data[$name];
        return null;
    }

    public function __isset($name) 
    {
        return isset($this->data[$name]);
    }

    public function __unset($name) 
    {
        unset($this->data[$name]);
    }

    public function getHidden()
    {
        return $this->hidden;
    }
}

$oPropTest = new PropertyTest();
$sField = 'my-field';

$oPropTest->$sField = 5;

var_dump($oPropTest);

Выходы:

bash-3.2$ php test-get-set.php
object(PropertyTest)#1 (1) {
  ["data":"PropertyTest":private]=>
  array(1) {
    ["my-field"]=>
    int(5)
  }
}

Один твик, который я бы предложил для вашей __get реализация заключается в использовании метода __isset, а не повторной реализации проверки (делая это двумя различными способами, как вы)

public function __get($name)
{
    if($this->__isset($name))
        return $this->data[$name];
    return null;
}

Относительно идеи возврата по ссылке из __get;он будет работать, но будет бесполезен ни с чем, кроме общедоступных атрибутов, поскольку частные и защищенные атрибуты не могут быть установлены напрямую через ссылку вне области действия класса.

$oPropTest = new PropertyTest();
$sField = 'my-field';

$oPropTest->$sField = 5;      // sets $oPropTest->my-field to 5 (effectively)
$iRef = $oPropTest->$sField;  // $iRef is a reference to $oPropTest->my-field
$iRef = 6;                    // this will not set $oPropTest->my-field since it's private
...