【问题标题】:Why and how the new keyword is being used with the already existing object of a class?为什么以及如何将 new 关键字与类的现有对象一起使用?
【发布时间】:2017-11-16 16:31:12
【问题描述】:

我正在使用 PHP 7.1.11

考虑下面的代码:

<?php
  class Test {
    static public function getNew() {
      return new static;
    }
  }

  class Child extends Test {}

  $obj1 = new Test();
  $obj2 = new $obj1;
?>

以上代码 sn-p 取自 PHP 手册。

从上面的代码中,我无法理解为什么以及如何将 new 关键字 与 class Test 的现有对象一起使用?

这样做的目的是什么?

这种new关键字的用法值得推荐吗?

如果你真的想将一个已经存在的类对象分配给某个变量,那不能通过简单地编写语句$obj2 = $obj1;来完成吗?

以下两个语句有什么区别?哪一个更好,应该首选?

$obj2 = new $obj1;
$obj2 = $obj1;

【问题讨论】:

    标签: php class object new-operator


    【解决方案1】:

    $obj2 = new $obj1;(创建与 $obj1 相同类的对象的新实例)!== $obj2 = $obj1;(创建 $obj2 对 $obj1 的引用)!== $obj2 = clone $obj1;(创建一个new $obj2 具有与原始对象相同的所有属性值,但作为新对象实例)

    对于我在上面的 cmets 中引用的 3 种不同情况,让我们创建一个简单的类并实例化它:

    class User {
        public $firstname;
        public $lastname;
    
        public function __construct($firstname = 'TEST', $lastname = 'USER') {
            $this->firstname = $firstname;
            $this->lastname = $lastname;
        }
    
        public function getName() {
            return implode(' ', [$this->firstname, $this->lastname]);
        }
    }
    
    // original instance of a User
    $obj1 = new User('Mark', 'Baker');
    var_dump($obj1->getName());    // Mark Baker
    

    现在,如果我们简单地为原始变量分配一个新变量,我们正在设置一个指向原始变量的指针(因为它是一个对象),类似于引用

    // Simply set reference to our original User
    $obj2 = $obj1;
    var_dump($obj2->getName());    // Mark Baker
    
    // And if we change properties of the instance, it changes for both because it's a reference
    $obj2->firstname = 'David Mark';
    var_dump($obj2->getName());    // David Mark Baker
    var_dump($obj1->getName());    // David Mark Baker
    

    对任何一个的任何更改都会反映在另一个中,因为它们指向同一个对象实例


    如果我们使用clone,那么我们正在创建一个全新的对象实例,但已经填充了原始的属性值

    // Clone the original object, this will create a new instance but will inherit property values of the original
    $obj3 = clone $obj1;
    var_dump($obj3->getName());    // David Mark Baker
    
    // But changing properties of the clone won't affect the original in any way
    $obj3->firstname = 'Mark';
    var_dump($obj3->getName());    // Mark Baker
    var_dump($obj1->getName());    // David Mark Baker
    

    现在,如果我们更改原始的属性,它不会影响克隆(反之亦然),因为它们是唯一的实例。


    我们有第三种情况,我们使用带有实例而不是类名的new。

    // Now create a new instance of the same type of object as your original User
    // If we had mandatory constructor arguments, then we'd have to provide them $obj4 = new $obj1('a', 'b');
    // But because they're optional, we  can get away with allowing the defaults
    
    $obj4 = new $obj1;
    var_dump($obj4->getName());    // TEST USER
    

    如果我们不知道$obj1 是什么类类型,那也没关系(尽管很容易找出来)。这将创建 $obj1 的任何类的全新实例,没有 clone 给出的属性继承,也不是像 $obj2 = $obj1 给出的引用......它仍然调用构造函数,所以我们必须传递任何强制构造函数参数(或得到错误)。

    【讨论】:

      【解决方案2】:

      new 运算符始终创建对象的新实例。它有一个参数,可以是硬编码的类名:

      $newObject = new MyClass();
      

      或包含类名的变量:

      $className = 'MyClass';
      $newObject = new $className();
      

      或您要创建的类型的对象的现有实例:

      $oldObject = new MyClass();
      $newObject = new $oldObject(); // Same as using "new MyClass();"
      

      你可能永远不会使用第三种情况。

      【讨论】:

      • 解决我的一个小疑问。在您的回答中,您到处都使用了“对象的实例”一词,但实际上“对象本身就是类的实例”。那么你如何制作/说“对象的实例(已经是类的实例)”?
      • 语义。如果有帮助,请将“对象的实例”替换为“实例化的对象”。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-09-10
      • 1970-01-01
      • 1970-01-01
      • 2020-12-18
      • 1970-01-01
      • 2014-11-26
      • 1970-01-01
      相关资源
      最近更新 更多