web-dev-qa-db-ja.com

PHP読み取り専用プロパティ?

PHPのDOMクラス(DOMNode、DOMEElementなど)を使用して、それらが本当に読み取り専用のプロパティを持っていることに気付きました。たとえば、DOMNodeの$ nodeNameプロパティを読み取ることはできますが、書き込むことはできません(PHPが致命的なエラーをスローした場合)。

PHPで独自の読み取り専用プロパティを作成するにはどうすればよいですか?

58
mazniak

次のようにできます:

class Example {
    private $__readOnly = 'hello world';
    function __get($name) {
        if($name === 'readOnly')
            return $this->__readOnly;
        user_error("Invalid property: " . __CLASS__ . "->$name");
    }
    function __set($name, $value) {
        user_error("Can't set property: " . __CLASS__ . "->$name");
    }
}

本当に必要な場合にのみ使用してください-通常のプロパティアクセスよりも遅いです。 PHPの場合、外部からプロパティを変更するにはセッターメソッドのみを使用するというポリシーを採用するのが最善です。

42
too much php

ただし、__ get()を使用してのみ公開されるプライベートプロパティは、オブジェクトのメンバーを列挙する関数(json_encode()など)には表示されません。

PHP json_encode()を使用してオブジェクトをJavascriptに定期的に渡します。データベースから多くのデータが取り込まれた複雑な構造を渡すのに適しているようです。これらのオブジェクトでパブリックプロパティを使用する必要がありますしたがって、このデータはそれを使用するJavascriptに取り込まれますが、これは、これらのプロパティがパブリックでなければならないことを意味します(したがって、同じ波長ではない別のプログラマー(またはおそらく夜が悪い夜に自分自身)がそれらを変更するリスクがあります)直接)。それらをプライベートにして__get()と__set()を使用すると、json_encode()はそれらを認識しません。

「読み取り専用」アクセシビリティキーワードがあると便利ではないでしょうか。

12
Matt

私はあなたがすでにあなたの答えを持っているのを見ます、しかしまだ見ているもののために:

すべての「読み取り専用」変数をprivateまたはprotectedとして宣言し、次のようにマジックメソッド__get()を使用します。

/**
 * This is used to fetch readonly variables, you can not read the registry
 * instance reference through here.
 * 
 * @param string $var
 * @return bool|string|array
 */
public function __get ($var)
{
    return ($var != "instance" && isset($this->$var)) ? $this->$var : false;
}

ご覧のように、このメソッドはユーザーが宣言されたすべての変数を読み取れるようにするため、$ this-> instance変数も保護しています。複数の変数をブロックするには、in_array()で配列を使用します。

5
Daniel

クラスのすべてのプロパティを外部から読み取り専用にする方法を次に示します。継承されたクラスには書き込みアクセス権があります;-)。

class Test {
    protected $foo;
    protected $bar;

    public function __construct($foo, $bar) {
        $this->foo = $foo;
        $this->bar = $bar;
    }

/**
 * All property accessible from outside but readonly
 * if property does not exist return null
 *
 * @param string $name
 *
 * @return mixed|null
 */
    public function __get ($name) {
        return $this->$name ?? null;
    }

/**
 * __set trap, property not writeable
 *
 * @param string $name
 * @param mixed $value
 *
 * @return mixed
 */
    function __set ($name, $value) {
        return $value;
    }
}

php7でテスト済み

シリアル化のためにプライベート/保護されたプロパティを公開する方法を探している場合、ゲッターメソッドを使用してそれらを読み取り専用にすることを選択した場合、これを行う方法があります(@Matt:jsonの例):

interface json_serialize {
    public function json_encode( $asJson = true );
    public function json_decode( $value );
}

class test implements json_serialize {
    public $obj = null;
    protected $num = 123;
    protected $string = 'string';
    protected $vars = array( 'array', 'array' );
    // getter
    public function __get( $name ) {
        return( $this->$name );
    }
    // json_decode
    public function json_encode( $asJson = true ) {
        $result = array();
        foreach( $this as $key => $value )
            if( is_object( $value ) ) {
                if( $value instanceof json_serialize )
                    $result[$key] = $value->json_encode( false );
                else
                    trigger_error( 'Object not encoded: ' . get_class( $this ).'::'.$key, E_USER_WARNING );
            } else
                $result[$key] = $value;
        return( $asJson ? json_encode( $result ) : $result );
    }
    // json_encode
    public function json_decode( $value ) {
        $json = json_decode( $value, true );
        foreach( $json as $key => $value ) {
            // recursively loop through each variable reset them
        }
    }
}
$test = new test();
$test->obj = new test();
echo $test->string;
echo $test->json_encode();
0
Precastic