是否可以从现有对象实例化?

时间:2017-08-25 16:15:55

标签: php oop

我偶然发现了这一点,并想知道这是否是预期的行为:

Interactive shell

php > class dog {
php {   public $name='doggy';
php {   public function speak() {
php {     echo "bark, bark! (my name is " . $this->name . ")\n";
php {   }
php { }
php >
php > $puppy = new dog;
php > $puppy->speak();
bark, bark! (my name is doggy)
php >
php > $taffy = new $puppy;
php > $taffy->speak();
bark, bark! (my name is doggy)
php >
php > $taffy->name = "Taffy";
php > $taffy->speak();
bark, bark! (my name is Taffy)
php >
php > $puppy->speak();
bark, bark! (my name is doggy)
php >

我的问题是关于这一行$taffy = new $puppy;

通常,我会编码$taffy = new dog;

我不希望通过实例化实例化来创建新对象......如果这有意义的话。

这是预期的功能,还是只是一次幸福的事故?

我在构建需要与几个不同的db表交谈的模型时发现了这一点,并且我使用依赖注入来传递数据库抽象:

class ShowConnectedTables {
  public function __constructor($db) {
    $this->modelOne = new ModelOne($db);
    $this->modelTwo = new ModelTwo($db);
  }
  // ... snip ...
}

$table = new ShowConnectedTables(new Database);

但是,有时候,在循环中取出ModelOne的行时,对ModelTwo的数据库调用可能会破坏对ModelOne行的提取。

是否可以接受
class ShowConnectedTables {
  public function __constructor($db) {
    $this->modelOne = new ModelOne($db);
    $this->modelTwo = new ModelTwo(new $db); // note new abstraction
  }
  // ... snip ...
}

$table = new ShowConnectedTables(new Database);

2 个答案:

答案 0 :(得分:2)

我从未见过这样或做过这件事。因此,我可能会避免它:如果它会导致其他开发人员看到它并刮擦他们的头(就像你一样),它可能是不值得的。毕竟,我看不出有什么理由让你特意这么做。

请不要恐慌地指出,虽然没有明确记录,但在PHP文档中有一个这样做的例子。 Example 5 on this page.

话虽如此,没有克隆人在进行:

class dog {
   public $name='doggy';
   public function speak() {
     echo "bark, bark! (my name is " . $this->name . ")\n<br>";
   }
    public function __clone() {
        print 'This is not called!';
        parent::__clone();
    }
}
$class = 'dog';
$puppy = new dog;
$puppy->name = 'Puppy';
$taffy = new $puppy;
if ( spl_object_hash( $taffy ) != spl_object_hash( $puppy ) )
    print 'not the same object';
$taffy->speak();

如果执行上述操作,您会发现对象不相同,并且永远不会调用__clone方法。此外,您的太妃糖将使用doggy的名称进行初始化,而不是Puppy。这似乎是有效的简写:

$class = get_class( $puppy );
$taffy = new $class;

答案 1 :(得分:1)

这不是创建对现有对象的新引用的问题。构造函数被执行,这意味着,这是一个新对象。我已经厌倦了:

<?php

class dog {
   public $name;
   public function __construct($name = '') {
       $this->name = $name ?: 'doggy';
   }
   public function speak() {
     echo "bark, bark! (my name is " . $this->name . ")\n";
   }
}

$puppy = new dog;
$puppy->speak(); #bark, bark! (my name is doggy)

$taffy = new $puppy('Snuffels');
$taffy->speak(); #bark, bark! (my name is Snuffels)

$taffy->name = "Taffy";
$taffy->speak(); #bark, bark! (my name is Taffy)

$puppy->speak(); #bark, bark! (my name is doggy)
echo $puppy;

IMO的原因是,您已经可以使用new selfnew parent之类的内容,请参阅http://php.net/manual/en/language.oop5.basic.php

  

在类上下文中,可以通过new selfnew parent创建新对象。

我认为,他们在new之后的事物中实现了类识别。但仍然是一个好的WTF:)