Эмулировать публичные / приватные свойства с помощью __get () и __set ()? - PullRequest
2 голосов
/ 13 августа 2010

Я писал класс, который использует __get() и __set() для хранения и извлечения элементов массива в мастер-массиве. У меня была проверка, чтобы сделать некоторые элементы незабываемыми, в основном, для воссоздания частных свойств.

Я заметил, что __get перехватывает все вызовы свойств класса. Это отстойно для меня, потому что я хотел иметь переменную private для внешнего мира (недоступную через get), но я пытался получить к ней доступ, напрямую ссылаясь на основной массив из класса. Конечно, мастер-массив не входит в белый список свойств gettable: (

Есть ли способ, которым я могу эмулировать публичные и приватные свойства в классе php, который использует __get() и __set()?

Пример:

<?
abstract class abstraction {

    private $arrSettables;
    private $arrGettables;
    private $arrPropertyValues;
    private $arrProperties;

    private $blnExists = FALSE;

    public function __construct( $arrPropertyValues, $arrSettables, $arrGettables ) {

        $this->arrProperties = array_keys($arrPropertyValues);
        $this->arrPropertyValues = $arrPropertyValues;
        $this->arrSettables = $arrSettables;
        $this->arrGettables = $arrGettables;
    }

    public function __get( $var ) {
        echo "__get()ing:\n";
        if ( ! in_array($var, $this->arrGettables) ) {
            throw new Exception("$var is not accessible.");
        }

        return $this->arrPropertyValues[$var];
    }

    public function __set( $val, $var ) {
        echo "__set()ing:\n";
        if ( ! in_array($this->arrSettables, $var) ) {
            throw new Exception("$var is not settable.");
        }

        return $this->arrPropertyValues[$var];
    }

} // end class declaration

class concrete extends abstraction {

    public function __construct( $arrPropertyValues, $arrSettables, $arrGettables ) {
        parent::__construct( $arrPropertyValues, $arrSettables, $arrGettables );
    }

    public function runTest() {

        echo "Accessing array directly:\n";
        $this->arrPropertyValues['color'] = "red";
        echo "Color is {$this->arrPropertyValues['color']}.\n";

        echo "Referencing property:\n";
        echo "Color is {$this->color}.\n";
        $this->color = "blue";
        echo "Color is {$this->color}.\n";

        $rand = "a" . mt_rand(0,10000000);
        $this->$rand = "Here is a random value";
        echo "'$rand' is {$this->$rand}.\n";

    }
}

try {
    $objBlock = & new concrete( array("color"=>"green"), array("color"),  array("color") );
    $objBlock->runTest();
} catch ( exception $e ) {
    echo "Caught Exeption $e./n/n";
}

// no terminating delimiter

$ php test.php
Accessing array directly:
__get()ing:
Caught Exeption exception 'Exception' with message 'arrPropertyValues is not accessible.' in /var/www/test.php:23
Stack trace:
#0 /var/www/test.php(50): abstraction->__get('arrPropertyValu...')
#1 /var/www//test.php(68): concrete->runTest()
#2 {main}.

Ответы [ 3 ]

2 голосов
/ 13 августа 2010

Есть ли способ, которым я могу эмулировать публичные и частные свойства в классе php, который использует __get () и __set ()?

Не напрямую (если вы скидываете debug_backtrace).

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

function __get($name) {        
    if (in_array($name, $this->privateProperties))
        throw new Exception("The property ". __CLASS__ . "::$name is private.");
    return $this->getPriv($name);
}

Внутри вашего класса вы будете вызывать getPriv, минуя, таким образом, __get.

1 голос
/ 13 августа 2010

Вместо того, чтобы вручную привлекать частные / защищенные свойства, вы можете использовать громоздкие PHP-методы отражения:

function __get($name) {

    $reflect = new ReflectionObject($this);
    $publics = $reflect->getProperties(ReflectionProperty::IS_PUBLIC);

    if (in_array($name, $publics)) {
         return $this->{$name};
    }
}
1 голос
/ 13 августа 2010

Сделать abstraction::$arrPropertyValues защищенным или делать то, что написал Артефакто (если вам нужны дополнительные проверки), за исключением того, что abstraction::getPriv() должен быть защищен.

...