質問
PHPのDOMクラス(DOMNode、DOMEElementなど)を使用すると、それらが本当に読み取り専用のプロパティを持っていることに気付きました。たとえば、DOMNodeの$ nodeNameプロパティを読み取ることはできますが、書き込むことはできません(PHPが致命的なエラーをスローした場合)。
PHPで独自の読み取り専用プロパティを作成するにはどうすればよいですか
解決
次のようにできます:
class Example {
private 次のようにできます:
<*>
これは、本当に必要な場合にのみ使用してください。通常のプロパティアクセスよりも低速です。 PHPの場合、外部からプロパティを変更するにはセッターメソッドのみを使用するというポリシーを採用するのが最適です。
_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の場合、外部からプロパティを変更するにはセッターメソッドのみを使用するというポリシーを採用するのが最適です。
他のヒント
ただし、__ get()を使用してのみ公開されるプライベートプロパティは、オブジェクトのメンバーを列挙する関数(json_encode()など)には表示されません。
私は、json_encode()を使用してPHPオブジェクトをJavascriptに定期的に渡します。これは、データベースから多数のデータが取り込まれた複雑な構造体を渡す良い方法だと思われるためです。これらのオブジェクトでパブリックプロパティを使用して、このデータがそれを使用するJavascriptに入力されるようにする必要がありますが、これは、それらのプロパティがパブリックでなければならないことを意味します(したがって、別のプログラマーが同じ波長ではない(またはおそらく自分が悪い夜を過ごした後)直接変更するかもしれません)。それらをプライベートにして__get()と__set()を使用すると、json_encode()はそれらを認識しません。
&quot;読み取り専用&quot;があると便利ではありませんか?アクセシビリティキーワード?
あなたはすでにあなたの答えを得ていますが、まだ見ている人のために:
すべての&quot; readonly&quot;を宣言するだけです変数を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-&gt;インスタンス変数も保護しています。複数の変数をブロックするには、in_array()で配列を使用します。
クラスのすべてのプロパティを外部から読み取り専用にする方法は次のとおりです。継承されたクラスには書き込みアクセス権があります;-)。
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();
Class PropertyExample {
private $m_value;
public function Value() {
$args = func_get_args();
return $this->getSet($this->m_value, $args);
}
protected function _getSet(&$property, $args){
switch (sizeOf($args)){
case 0:
return $property;
case 1:
$property = $args[0];
break;
default:
$backtrace = debug_backtrace();
throw new Exception($backtrace[2]['function'] . ' accepts either 0 or 1 parameters');
}
}
}
これは、プロパティの取得/設定の処理方法です。Value()を読み取り専用にしたい場合は、次のようにします:
return $this->m_value;
Value()関数が現在取得または設定する場所