简体   繁体   English

可以从现有对象实例化吗?

[英]Acceptable to instantiate from an existing object?

I discovered this by accident, and was wondering if this is expected behaviour: 我偶然发现了这个,并且想知道这是否是预期的行为:

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 >

My question is about the line, $taffy = new $puppy; 我的问题是关于这条线, $taffy = new $puppy;

Normally, I would have coded $taffy = new dog; 通常,我会用$taffy = new dog;编码$taffy = new dog;

I wouldn't have expected to be able to create a new object by instantiating from an instantiation... if that makes any sense. 我不希望能够通过实例化实例来创建新对象……如果这有意义的话。

Is this expected functionality, or just a happy accident? 这是预期的功能,还是不幸的事故?


I discovered this when building a model that needed to talk to several different db tables, and I use dependency injection to pass the database abstraction: 我在构建需要与几个不同的数据库表进行通信的模型时发现了这一点,并且我使用依赖注入来传递数据库抽象:

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

$table = new ShowConnectedTables(new Database);

Sometimes, though, a database call to ModelTwo in the middle of a loop fetching ModelOne's rows could clobber the fetching of ModelOne's rows. 但是,有时,在循环中间读取ModelOne的行时,对ModelTwo的数据库调用可能会阻碍对ModelOne的行的提取。 So is it acceptable to 所以可以接受

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);

I've never seen this or done this. 我从未见过或做过此事。 As a result, I would probably avoid it: if it is going to cause other developers to look at it and scratch their heads (just like you did), it probably isn't worth it. 结果,我可能会避免:如果这将导致其他开发人员看它并挠头(就像您所做的那样),则可能不值得。 I can't see any reason why you would specifically have to do this, after all. 毕竟,我看不出您为什么要专门这样做的任何原因。

Don't Panic has pointed out that, while not explicitly documented, there is an example of doing this in the PHP documentation. 不要恐慌指出,尽管没有明确记录,但PHP文档中有一个执行此操作的示例。 Example 5 on this page. 此页面上的示例5。

That being said, there is no cloning going on: 话虽如此,没有克隆正在进行:

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();

If you do the above you will find that the objects are not the same and the __clone method is never called. 如果执行上述操作,您会发现对象不相同,并且永远不会调用__clone方法。 Also, your taffy will be initialized with the name of doggy , not Puppy . 另外,您的太妃糖将使用doggy而不是Puppy的名称进行初始化。 It seems this is effectively shorthand for: 看来这实际上是以下方面的简写:

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

This is not a matter of creating a new reference to existing object. 这不是创建对现有对象的新引用的问题。 The constructor is executed, so that means, this is a new object. 构造函数被执行,这意味着这是一个新对象。 I've tired it: 我已经累了:

<?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;

The reason IMO is, that you can already use things like new self or new parent , see http://php.net/manual/en/language.oop5.basic.php IMO的原因是,您已经可以使用诸如new selfnew parent类的东西,请参见http://php.net/manual/en/language.oop5.basic.php

In the class context, it is possible to create a new object by new self and new parent . 在类上下文中,可以通过new selfnew parent创建一个新对象。

I assume, that they implement a class recognition from things after new . 我假设,他们从new之后的事物中实现了类识别。 But still a good WTF :) 但是还是一个不错的WTF :)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM