最近、「php Core Technology and Best Practices」という本を読んでいます。この本の最初の章では、__call() メソッドを使用して単純な文字列チェーン操作を実装できると述べています。たとえば、次の例では文字列をフィルター処理します。長さの演算は一般的に次のように記述されます:
strlen(trim($str));
それでは、次の記述は実現できるでしょうか?
$str->trim()->strlen();
今すぐ試してみましょう。
チェーン操作は、率直に言えば、実際にはオブジェクトを呼び出すメソッドのチェーンです。文字列チェーン操作を実装する必要があるため、文字列クラスを実装してから、このクラスのオブジェクトを呼び出す必要があります。 String クラスに対する私の期待は次のとおりです。(1) オブジェクトを作成するときに、文字列をオブジェクトのプロパティに割り当てることができ、このプロパティにアクセスして値を読み取ることができます。(2) trim( を呼び出すことができます。 ) と strlen( ) メソッド; (3) このように $str->trim()->strlen() メソッドを呼び出すこともできます。
上記の項目 (1) は、文字列クラスの基本的な要件です。最初にこれを実装します:
class String { public $value; public function __construct($str=null) { $this->value = $str; } }
次のことを試すことができます:
1 $str = new String('01389');
2 echo $str->value;
次に項目 2 を見て、最初に実装します。 $str->trim() については、本書のアイデアを参照してください。__call メソッドをトリガーしてから call_user_func を実行します。コードは次のとおりです:
class String { public $value; public function __construct($str=null) { $this->value = $str; } public function __call($name, $args) { $this->value = call_user_func($name, $this->value, $args[0]); return $this; } }
テスト済み:
1 $str = new String('01389');
2 echo $str->trim('0')->value;
結果
上記で注意する必要があるのは 12 行目です: $this->value = call_user_func($name, $this->value, $args[0]);コールバック関数 (つまり、ここでは trim) の最後の 2 つはコールバック関数 (tim) のパラメーターであり、パラメーターの順序は逆になりません。 $args は配列なので注意が必要です。
Strlen() も記事 2 で実装する必要があります。現時点では、上記のコードの 13 行目が非常に重要です: return $this; その機能は、12 行目で Trim() を呼び出して文字列を処理し、再度実行することです。 value 属性に値が割り当てられ、現在のオブジェクトへの参照が返されるため、オブジェクト内の他のメソッドが属性値に対して連続操作を実行できるため、連鎖操作が実現します。 $str->strlen() は次のように実装されます:
class String { public $value; public function __construct($str=null) { $this->value = $str; } public function __call($name, $args) { $this->value = call_user_func($name, $this->value, $args[0]); return $this; } public function strlen() { return strlen($this->value); } }
テスト済み:
1 $str = new String('01389');
2 echo $str->strlen();
結果:
チェーン操作:
echo $str->trim('0')->strlen();
結果:
class String { public $value; public function __construct($str=null) { $this->value = $str; } public function trim($t) { $this->value = trim($this->value, $t); return $this; } public function strlen() { return strlen($this->value); } }
チェーン操作の鍵は操作を完了することです最後に $this を返します。
さらに、この記事は庭のこの記事に触発され、call_user_func() の実装を call_user_func_array() に置き換え、__call() メソッドを次のように変更しています。
public function __call($name, $args) { array_unshift($args, $this->value); $this->value = call_user_func_array($name, $args); return $this; }
効果は上記の __call() メソッドと同じなので、コードは前の実装よりも洗練されているように見えます。
概要:
__call() は、オブジェクトがアクセスできないメソッドを呼び出すときにトリガーされるため、クラスの動的メソッドの作成を実現し、PHP のメソッドのオーバーロード機能を実現できますが、実際には糖衣構文 (__construct) ( ) 方式も同様です)。
では、__call() のような糖衣構文がなければ、動的メソッドやチェーン操作の作成は実現できるでしょうか?これには、クラスメソッドが存在し、呼び出せるかどうかが含まれると思います。これは、method_exists、is_callable、get_class_methods などのメソッドを使用して実現できます。また、オブジェクトの作成時に属性に値を割り当てる (初期化) ことも含まれます。構文シュガーは確かに便利ですが、必須ではありません。時間があるときにもう一度勉強しましょう。