簡體   English   中英

PHP使用靜態函數創建帶有繼承的新實例

[英]PHP use static function to create new instance w/ Inheritance

所以我從Laravel那里得到了這個主意。 使用Laravel,您可以執行以下操作。

$user = new User;
$user->where('name', 'george')->get();

// which is the same as...

User::where('name', 'george')->get();

因此,我猜測User類具有__callStatic設置,因此它使新實例成為后備。 我能夠使用以下代碼復制該代碼。

class Driver
{
  protected static $instance = null;

  public static function __callStatic($name, $args) {
    $classname = get_called_class();
    if (empty(static::$instance)) static::$instance = new $classname;
    return static::$instance->$name(...$args);
  }
}

但是,當我嘗試多次繼承該類時,就會出現問題。 我希望所有類都能夠繼承__callStatic並能夠靜態調用其祖先的任何公共函數。

class A extends Driver
{

  public function hello() {
    echo "hello";
    return $this;
  }

  public function world() {
    echo " world";
    return $this;
  }

}

class B extends A 
{
  public function name() {
    echo "\nMy Name is George";
    return $this;
  }
}

class C extends B 
{
  // class can be empty
}

C::hello()->world()->name();

// returns: hello world
// My name is George

您遇到的問題是由於$ instance屬性是靜態的,並且在父類上聲明的。 您的項目中只有一個實例屬性,它是Driver的類屬性。

有幾種解決方法。 您可以在子類上定義$ instance,將Driver :: $ instance作為地圖(數組)作為[className => instance],或者更好的是,完全擺脫該全局狀態;)

無論如何,具有“類似單例”的$ instance結構的整個概念可能會在以后引起更多的問題。 考慮以下示例:

class Foo extends Driver
{
  private $name;
  public function named(string $name) : self
  {
    $this->name = $name;
    return $this;
  }
  public function name() : string
  {
    return $this->name;
  }
}

$alice = Foo::named('Alice');
$bob = Foo::named('Bob');

echo $alice->name(); // Outputs "Bob"!

$ alice仍然指向原始實例,但是由於Foo :: named('bob')將名稱bob分配給了相同的實例,因此您不小心將Alice重命名為Bob。

您可能正在尋找的更像是:

abstract class Driver
{
  public static function __callStatic(string $name, array $arguments)
  {
    $instance = new static;
    $instance->$name(...$arguments);
    return $instance;
  }
}

這樣,您每次都會創建新實例。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM