PHP使用静态函数来创建具有继承的新实例

时间:2018-01-27 19:38:44

标签: php laravel 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

1 个答案:

答案 0 :(得分:1)

您遇到的问题是由于$ instance属性是静态的,并在父类上声明。项目中只有一个实例属性,它是Driver的类属性。

有几种方法可以解决这个问题。您可以在子类上定义$ instance,将Driver :: $ instance作为map(array)作为[className =>实例],或者更好的是,完全摆脱那片全球状态;)

拥有" singleton-like"无论如何,$ 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;
  }
}

这样,您每次都会创建新实例。