ベリーの答えを拡張するために、アクセスレベルを保護に設定すると、明示的に宣言されたプロパティで__getと__setを使用でき(少なくともクラスの外部でアクセスした場合)、速度がかなり遅くなります。別の質問からのコメントを引用しますこのトピックについて、とにかくそれを使用するためのケースを作ります:
__getはカスタムget関数(同じことを行う)よりも遅いことに同意します。これは__get()の時間0.0124455であり、この0.0024445は10000ループ後のカスタムget()の時間です。– melsi 2012年11月23日22:32ベストプラクティス:PHPマジックメソッド__setおよび__get
Melsiのテストによると、かなり遅いのは約5倍遅いです。これは間違いなくかなり遅いですが、テストでは、このメソッドを使用してプロパティに10,000回アクセスでき、ループ反復の時間を約1/100秒でカウントできることにも注意してください。定義されている実際のgetおよびsetメソッドと比較するとかなり遅く、それは控えめな表現ですが、物事の壮大なスキームでは、5倍遅い場合でも実際に遅くなることはありません。
操作の計算時間はまだごくわずかであり、実際のアプリケーションの99%では考慮する価値がありません。実際に回避する必要があるのは、1回のリクエストで実際に10,000回を超えるプロパティにアクセスする場合のみです。トラフィックの多いサイトは、アプリケーションを実行し続けるためにさらにいくつかのサーバーを起動する余裕がない場合、本当に悪いことをしています。アクセス率が問題となるトラフィックの多いサイトのフッターにある1行のテキスト広告は、おそらくそのテキスト行を持つ1,000台のサーバーのファームに支払う可能性があります。アプリケーションのプロパティアクセスには100万分の1秒かかるため、エンドユーザーはページの読み込みに何がそんなに時間がかかるのか疑問に思うことは決してありません。
私はこれを.NETのバックグラウンドから来た開発者として話すと言いますが、消費者に見えないgetおよびsetメソッドは.NETの発明ではありません。それらは単にそれらのないプロパティではなく、これらの魔法のメソッドは、プロパティのバージョンを「プロパティ」と呼ぶことさえできるPHPの開発者の節約の恩恵です。また、PHP用のVisual Studio拡張機能は、保護されたプロパティを備えたインテリセンスをサポートしています。そのトリックを念頭に置いて、私は思います。このように魔法の__getメソッドと__setメソッドを使用する十分な数の開発者がいると、PHP開発者は開発者コミュニティに対応するために実行時間を調整すると思います。
編集:理論的には、保護されたプロパティはほとんどの状況で機能するように見えました。実際には、クラス定義および拡張クラス内のプロパティにアクセスするときに、ゲッターとセッターを使用したいと思うことがよくあります。より良い解決策は、他のクラスを拡張するときの基本クラスとインターフェースです。したがって、基本クラスから実装クラスに数行のコードをコピーするだけです。プロジェクトの基本クラスでもう少し作業を行っているので、現時点で提供するインターフェイスはありませんが、リフレクションを使用してプロパティを削除および移動する魔法のプロパティを取得および設定する、テストされていないストリップダウンクラス定義を次に示します。保護されたアレイ:
class Component {
protected $properties = array();
public function __get($name) {
$caller = array_shift(debug_backtrace());
$max_access = ReflectionProperty::IS_PUBLIC;
if (is_subclass_of($caller['class'], get_class($this)))
$max_access = ReflectionProperty::IS_PROTECTED;
if ($caller['class'] == get_class($this))
$max_access = ReflectionProperty::IS_PRIVATE;
if (!empty($this->properties[$name])
&& $this->properties[$name]->class == get_class()
&& $this->properties[$name]->access <= $max_access)
switch ($name) {
default:
return $this->properties[$name]->value;
}
}
public function __set($name, $value) {
$caller = array_shift(debug_backtrace());
$max_access = ReflectionProperty::IS_PUBLIC;
if (is_subclass_of($caller['class'], get_class($this)))
$max_access = ReflectionProperty::IS_PROTECTED;
if ($caller['class'] == get_class($this))
$max_access = ReflectionProperty::IS_PRIVATE;
if (!empty($this->properties[$name])
&& $this->properties[$name]->class == get_class()
&& $this->properties[$name]->access <= $max_access)
switch ($name) {
default:
$this->properties[$name]->value = $value;
}
}
function __construct() {
$reflected_class = new ReflectionClass($this);
$properties = array();
foreach ($reflected_class->getProperties() as $property) {
if ($property->isStatic()) { continue; }
$properties[$property->name] = (object)array(
'name' => $property->name, 'value' => $property->value
, 'access' => $property->getModifier(), 'class' => get_class($this));
unset($this->{$property->name}); }
$this->properties = $properties;
}
}
コードにバグがある場合はお詫び申し上げます。