一個關於 PHP 的 new 的小問題的探究

問題原由

前兩天有人在羣裏說了一個關於 newstdClass 的問題,具體表現以下:php

<?php
$a = new stdClass;
$b = new $a;
var_dump($a, $b);

這段代碼是能夠正確運行的,而且 $a$b 是兩個不一樣的空對象。即便在 new $a 以前給 $a 添加屬性並賦值,$b 也始終是一個的空對象。測試

因此問題就是:爲何空對象還能夠跟在 new 後面,stdClass 有什麼特殊的地方嗎?code

實際表現

其實主要稍加驗證就能知道,其實這和 stdClass 並無什麼關係,徹底是 new 的行爲決定的,好比在 psysh 上作一下簡單的測試:對象

>>> $a = new Reflection;
=> Reflection {#174}
>>> $b = new $a;
=> Reflection {#177}

這裏我是 new 了一個 Reflection 類的實例,和 stdClass 的表現沒有區別。固然也能夠自定義一個類:get

>>> class Test { public $foo = 1; }
=> null
>>> $a = new Test
=> Test {#178
     +foo: 1,
   }
>>> $a->foo = 2;
=> 2
>>> $b = new $a;
=> Test {#180
     +foo: 1,
   }

從這個例子中咱們能夠清楚的看到,改變 $a 的屬性對 $b 沒有任何影響(到這裏也能夠順便思考一下 PHP 的一個關鍵字:clone)。源碼

既然已經知道了表現,也能夠獲得結論:經過一個類的對象 new 出一個新對象等同於 new 原對象的類。io

緣由

那麼 PHP 是什麼樣的實現形成了這種表現呢?仍是從源碼入手來解析這個問題。class

其實從源碼中,咱們能夠直奔 zend_vm_def.h 中找到答案,在關於 ZEND_FETCH_CLASS 這個 opcode 的解釋中,咱們能夠看到如下內容:文件

ZEND_VM_HANDLER(109, ZEND_FETCH_CLASS, ANY, CONST|TMPVAR|UNUSED|CV)
{
        ...
        if (OP2_TYPE == IS_CONST) {
            ...
        } else if (Z_TYPE_P(class_name) == IS_OBJECT) {
            Z_CE_P(EX_VAR(opline->result.var)) = Z_OBJCE_P(class_name);
        } ...
        ...
}

去掉一些干擾的上下文,上面的內容很清晰的呈現出一個解釋:若是取到的 class_name 是一個對象,則經過 Z_OBJCE_P 的宏找到它的類。因此上面的表現解釋起來就很容易了。思考

這自己是一個很簡單的問題,不用往復雜了去想。若是想知道具體的 new 的實現,能夠到 zend_compile.c 文件中去查看 zend_compile_new 的實現。

相關文章
相關標籤/搜索