Berry の回答を拡張するには、アクセス レベルを protected に設定すると、明示的に宣言されたプロパティで __get および __set を使用できるようになり (少なくともクラス外でアクセスする場合)、速度がかなり遅くなります。別の質問からコメントを引用します。このトピックについて、とにかくそれを使用するケースを作成します。
__get はカスタム get 関数 (同じことを行う) よりも遅いことに同意します。これは __get() の時間で 0.0124455 であり、この 0.0024445 は 10000 ループ後のカスタム get() の時間です。— Melsi 12 年 11 月 23 日 22:32 に
Melsi のテストによると、かなり遅いとは約 5 倍遅くなります。これは間違いなくかなり遅いですが、テストでは、このメソッドを使用してプロパティに 10,000 回アクセスできることが示されていることにも注意してください。定義された実際の get および set メソッドと比較するとかなり遅く、それは控えめな表現ですが、物事の全体的なスキームでは、5 倍遅くても実際に遅いことはありません。
操作の計算時間はまだ無視できる程度であり、実際のアプリケーションの 99% で考慮する価値はありません。本当に避けるべき唯一のケースは、実際に 1 回のリクエストで 10,000 回以上プロパティにアクセスする場合です。トラフィックの多いサイトは、アプリケーションを実行し続けるためにさらに数台のサーバーを投入する余裕がない場合、非常に悪いことをしています。アクセス率が問題となるトラフィックの多いサイトのフッターに表示される 1 行のテキスト広告は、おそらくそのテキスト行で 1,000 台のサーバー ファームの料金を支払うことができます。アプリケーションのプロパティへのアクセスには 100 万分の 1 秒かかるため、エンド ユーザーは、ページの読み込みに時間がかかっている原因を知りたいと思って指をタップすることはありません。
私は .NET のバックグラウンドを持つ開発者としてこれを言いますが、消費者に見えない get メソッドと set メソッドは .NET の発明ではありません。それらは単にそれらなしではプロパティではありません。これらの魔法のメソッドは、プロパティのバージョンを「プロパティ」と呼んでさえも、PHP 開発者の救いの恵みです。また、PHP 用の Visual Studio 拡張機能は、保護されたプロパティを使用して IntelliSense をサポートしていますが、そのトリックを念頭に置いていると思います。このように魔法の __get および __set メソッドを使用する十分な数の開発者がいれば、PHP 開発者は実行時間を調整して開発者コミュニティに対応できると思います。
編集: 理論的には、保護されたプロパティはほとんどの状況で機能するように見えました。実際には、クラス定義および拡張クラス内のプロパティにアクセスするときに、getter および setter を使用したい場合が多いことがわかります。より良い解決策は、他のクラスを拡張するときの基本クラスとインターフェイスです。そのため、基本クラスから実装クラスに数行のコードをコピーするだけで済みます。私は自分のプロジェクトの基本クラスでもう少し作業を行っているので、現在提供するインターフェイスはありませんが、リフレクションを使用してプロパティを削除および移動する魔法のプロパティを取得および設定する未テストのストリップダウン クラス定義を次に示します。保護された配列:
/** Base class with magic property __get() and __set() support for defined properties. */
class Component {
/** Gets the properties of the class stored after removing the original
* definitions to trigger magic __get() and __set() methods when accessed. */
protected $properties = array();
/** Provides property get support. Add a case for the property name to
* expand (no break;) or replace (break;) the default get method. When
* overriding, call parent::__get($name) first and return if not null,
* then be sure to check that the property is in the overriding class
* before doing anything, and to implement the default get routine. */
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;
}
}
/** Provides property set support. Add a case for the property name to
* expand (no break;) or replace (break;) the default set method. When
* overriding, call parent::__set($name, $value) first, then be sure to
* check that the property is in the overriding class before doing anything,
* and to implement the default set routine. */
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;
}
}
/** Constructor for the Component. Call first when overriding. */
function __construct() {
// Removing and moving properties to $properties property for magic
// __get() and __set() support.
$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;
}
}
コードにバグがある場合は申し訳ありません。