【发布时间】:2013-03-19 07:01:22
【问题描述】:
遇到过很多次,不知道为什么,这让我很好奇。一些类在声明之前就可以工作,而另一些则不能;
示例 1
$test = new TestClass(); // top of class
class TestClass {
function __construct() {
var_dump(__METHOD__);
}
}
输出
string 'TestClass::__construct' (length=22)
示例 2
当一个类扩展另一个类或实现任何接口时
$test = new TestClass(); // top of class
class TestClass implements JsonSerializable {
function __construct() {
var_dump(__METHOD__);
}
public function jsonSerialize() {
return json_encode(rand(1, 10));
}
}
输出
Fatal error: Class 'TestClass' not found
示例 3
让我们尝试上面相同的类,但改变位置
class TestClass implements JsonSerializable {
function __construct() {
var_dump(__METHOD__);
}
public function jsonSerialize() {
return json_encode(rand(1, 10));
}
}
$test = new TestClass(); // move this from top to bottom
输出
string 'TestClass::__construct' (length=22)
示例 4(我也使用 class_exists 进行了测试)
var_dump(class_exists("TestClass")); //true
class TestClass {
function __construct() {
var_dump(__METHOD__);
}
public function jsonSerialize() {
return null;
}
}
var_dump(class_exists("TestClass")); //true
一旦实现JsonSerializable(或任何其他)
var_dump(class_exists("TestClass")); //false
class TestClass implements JsonSerializable {
function __construct() {
var_dump(__METHOD__);
}
public function jsonSerialize() {
return null;
}
}
var_dump(class_exists("TestClass")); //true
还检查了操作码withoutJsonSerializable
line # * op fetch ext return operands
---------------------------------------------------------------------------------
3 0 > SEND_VAL 'TestClass'
1 DO_FCALL 1 $0 'class_exists'
2 SEND_VAR_NO_REF 6 $0
3 DO_FCALL 1 'var_dump'
4 4 NOP
14 5 > RETURN 1
还检查了操作码withJsonSerializable
line # * op fetch ext return operands
---------------------------------------------------------------------------------
3 0 > SEND_VAL 'TestClass'
1 DO_FCALL 1 $0 'class_exists'
2 SEND_VAR_NO_REF 6 $0
3 DO_FCALL 1 'var_dump'
4 4 ZEND_DECLARE_CLASS $2 '%00testclass%2Fin%2FaDRGC0x7f563932f041', 'testclass'
5 ZEND_ADD_INTERFACE $2, 'JsonSerializable'
13 6 ZEND_VERIFY_ABSTRACT_CLASS $2
14 7 > RETURN 1
问题
- 我知道
Example 3有效,因为该类是在其启动之前声明的,但为什么Example 1首先会有效? - 扩展或接口的整个过程如何在 PHP 中工作以使一个有效而另一个无效?
- 示例 4 中究竟发生了什么?
-
Opcodes应该让事情变得清晰,但只是让它变得更复杂,因为class_exists在TestClass之前被调用,但情况正好相反。
【问题讨论】:
-
我以前也想知道这个,我从
Iterator和朋友那里知道的。 -
如果实现的类也存在于同一个文件中,这会有所不同吗?也许这与 php 查找引用类的方式有关。 (查看文件,甚至可能访问 _autoload(),最后查看类的本机代码)
-
即使包含一个类也是同样的问题......
-
1) 它是无条件的,2) 接口必须在使用前声明,3) 以 JsonSerializeable 为条件,参见 2),4) DO_FCALL 需要 SEND_VAL 才能实际运行,考虑任何函数调用任何语言:函数(一、二、三)、一、二和三必须在 function() 发生之前有一个值。