문제 원인
이틀 전 그룹 내 new 및 stdClass에 대한 질문이 있었습니다. 구체적인 성능은 다음과 같습니다.
<?php $a = new stdClass; $b = new $a; var_dump($a, $b);
이 코드는 올바르게 실행될 수 있습니다. 그리고 $a와 $b는 서로 다른 두 개의 빈 객체입니다. 새로운 $a 이전에 $a에 속성을 추가하고 값을 할당하더라도 $b는 항상 빈 개체입니다.
그래서 질문은: 왜 빈 객체가 new를 따를 수 있습니까? stdClass에 특별한 것이 있습니까?
실제 성능
사실 이는 약간의 검증을 통해 알 수 있습니다. 사실 이는 stdClass와는 아무런 관련이 없습니다. 예를 들어 new의 동작에 의해 완전히 결정됩니다. psysh에서 간단한 테스트를 수행해 보세요.
>>> $a = new Reflection; => Reflection {#174} >>> $b = new $a; => Reflection {#177}
여기서 stdClass와 동일하게 동작하는 Reflection 클래스의 새 인스턴스를 만들었습니다. 물론, 클래스를 사용자 정의할 수도 있습니다.
>>> 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와 동일합니다.
원인
그럼 어떤 종류의 PHP 구현으로 인해 이러한 동작이 발생합니까? 이 문제를 분석하기 위해 소스 코드부터 시작해 보겠습니다.
사실 소스 코드에서 zend_vm_def.h로 바로 가서 답을 찾을 수 있습니다. opcode ZEND_FETCH_CLASS에 대한 설명에서 다음을 볼 수 있습니다.
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의 구현을 볼 수 있습니다.