PHPの遅延静的バインディングとは正確には何ですか?
8 に答える
PHP マニュアルのLate Static Bindingsを読む必要があります。とはいえ、簡単にまとめてみます。
self
基本的には、キーワードが同じ継承規則に従っていない という事実に要約されます。self
常に、それが使用されているクラスに解決されます。これは、親クラスでメソッドを作成し、それを子クラスから呼び出すと、self
期待どおりに子を参照しないことを意味します。
static
遅延静的バインディングは、この特定の欠点に対処するキーワードの新しい使用法を導入します。を使用する場合static
、最初に使用するクラスを表します。ランタイム クラスに「バインド」します。
これらは、その背後にある 2 つの基本的な概念です。が実行されているときself
の操作方法は微妙な場合があるため、詳しく説明するよりも、マニュアル ページの例を参照することを強くお勧めします。各キーワードの基本を理解したら、どのような結果が得られるかを確認するには、例が必要です。parent
static
static
PHPから: Late Static Bindings - Manual :
PHP 5.3.0 の時点で、PHP は、静的継承のコンテキストで呼び出されたクラスを参照するために使用できる遅延静的バインディングと呼ばれる機能を実装しています。
遅延静的バインディングは、実行時に最初に呼び出されたクラスを参照するキーワードを導入することで、その制限を解決しようとします。...新しいキーワードを導入するのではなく、
static
すでに予約されているものを使用することにしました。
例を見てみましょう:
<?php
class Car
{
public static function run()
{
return static::getName();
}
private static function getName()
{
return 'Car';
}
}
class Toyota extends Car
{
public static function getName()
{
return 'Toyota';
}
}
echo Car::run(); // Output: Car
echo Toyota::run(); // Output: Toyota
?>
遅延静的バインディングは、最後の「非転送呼び出し」で指定されたクラスを格納することによって機能します。
::
静的メソッド呼び出しの場合、これは明示的に名前が付けられたクラスです (通常は演算子の左側にあります)。非静的メソッド呼び出しの場合は、オブジェクトのクラスです。「転送呼び出し」はself::
、parent::
、static::
、またはクラス階層を上に行く場合は によって導入される静的なものですforward_static_call()
。この関数get_called_class()
を使用して、呼び出されたクラスの名前を持つ文字列を取得し、static::
そのスコープを導入できます。
非常に明白な動作はありません。
次のコードは「alphabeta」を生成します。
class alpha {
function classname(){
return __CLASS__;
}
function selfname(){
return self::classname();
}
function staticname(){
return static::classname();
}
}
class beta extends alpha {
function classname(){
return __CLASS__;
}
}
$beta = new beta();
echo $beta->selfname(); // Output: alpha
echo $beta->staticname(); // Output: beta
ただし、ベータ クラスから classname 関数の宣言を削除すると、結果として 'alphaalpha' が得られます。
本から引用しています:「PHPマスターは最先端のコードを書く」。
遅延静的バインディングは、php 5.3 で導入された機能です。親クラスから静的メソッドを継承し、呼び出される子クラスを参照できます。
これは、静的メソッドを持つ抽象クラスを持つことができ 、self::method() の代わりにstatic::method()表記を使用して子クラスの具体的な実装を参照できることを意味します。
公式の php ドキュメントも参照してください: http://php.net/manual/en/language.oop5.late-static-bindings.php
Late Static Binding を説明する最も明確な方法は、実際の例を使用することです。Template メソッド パターンで使用しています。下記参照。
abstract class AbstractTemplate {
public const AWESOME_LIST = [''];
public function someFunction(): void {
$awesomeList = $this->getAwesomeList();
// OUTPUT: ['harry','henk','john'];
var_dump($awesomeList);
}
/**
* This function gets static constants from CHILD classes
*/
public function getAwesomeList(): array
{
return static::AWESOME_LIST;
}
}
class ConcreteTemplate extends AbstractTemplate {
public const AWESOME_LIST = ['harry','henk','john'];
public function someFunction(): void {
parent::someFunction();
}
}
$concreteTemplate = new ConcreteTemplate();
$concreteTemplate->someFunction();
static
method のキーワードに注意してくださいgetAwesomeList
。少し変更してみましょう。
public function getAwesomeList(): array
{
return self::AWESOME_LIST;
}
var_dump
atの出力は次のようにsomeFunction
なります。
array (size=1)
0 => string '' (length=0)
static
キーワードはシングルトン デザイン パターンで使用されます。リンクを参照してください: https://refactoring.guru/design-patterns/singleton/php/example
違いを示す最も簡単な例。
注意、self::$c
class A
{
static $c = 7;
public static function getVal()
{
return self::$c;
}
}
class B extends A
{
static $c = 8;
}
B::getVal(); // 7
遅延静的バインディング、static::$cに注意
class A
{
static $c = 7;
public static function getVal()
{
return static::$c;
}
}
class B extends A
{
static $c = 8;
}
B::getVal(); // 8
例えば:
abstract class Builder {
public static function build() {
return new static;
}
}
class Member extends Builder {
public function who_am_i() {
echo 'Member';
}
}
Member::build()->who_am_i();