gpt4 book ai didi

php - 类扩展或接口(interface)如何工作?

转载 作者:IT王子 更新时间:2023-10-29 01:06:02 26 4
gpt4 key购买 nike

遇到过很多次,不知道为什么,这让我很好奇。一些类在声明之前就可以工作,而另一些则不能;

示例 1

$test = new TestClass(); // top of class
class TestClass {
function __construct() {
var_dump(__METHOD__);
}
}

输出

 string 'TestClass::__construct' (length=22)

示例 2

当一个类扩展另一个类或实现任何接口(interface)时

$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

还检查了操作码 without JsonSerializable

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

还检查了操作码 with JsonSerializable

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 中,扩展或接口(interface)的整个过程如何使一个有效而另一个无效?
  • 示例 4 中究竟发生了什么?
  • Opcodes 应该让事情变得清晰,但只是让它变得更复杂,因为 class_existsTestClass 之前被调用,但情况恰恰相反。

最佳答案

我找不到关于 PHP 类定义的文章;但是,我想它与 User-defined functions 完全相同您的实验表明了这一点。

函数在被引用之前不需要被定义,除了当一个函数被有条件地定义时,如下面的两个例子所示。当以条件方式定义函数时;它的定义必须在被调用之前进行处理。

<?php

$makefoo = true;

/* We can't call foo() from here
since it doesn't exist yet,
but we can call bar() */

bar();

if ($makefoo) {
function foo()
{
echo "I don't exist until program execution reaches me.\n";
}
}

/* Now we can safely call foo()
since $makefoo evaluated to true */

if ($makefoo) foo();

function bar()
{
echo "I exist immediately upon program start.\n";
}

?>

对于类也是如此:

  • 示例 1 有效,因为该类不以其他任何条件为条件。
  • 示例 2 失败,因为该类以 JsonSerializable 为条件。
  • 示例 3 有效,因为该类在被调用之前已正确定义。
  • 示例 4 第一次为 false,因为该类是有条件的,但后来成功,因为该类已加载。

通过实现一个接口(interface)或从另一个文件扩展另一个类 (require),该类是有条件的。我称它为有条件的,因为该定义现在依赖于另一个定义。

想象一下 PHP 解释器首先查看这个文件中的代码。它看到一个非条件类和/或函数,所以它继续并将它们加载到内存中。它会看到一些有条件的并跳过它们。

然后解释器开始解析页面执行。在示例 4 中,它到达 class_exists("TestClass") 指令,检查内存,然后说不,我没有。如果没有它,因为它是有条件的。它继续执行指令,查看条件类并执行指令以将类实际加载到内存中。

然后它下降到最后一个 class_exists("TestClass") 并看到该类确实存在于内存中。

在读取您的操作码时,TestClass 不会在 class_exist 之前被调用。您看到的是发送 value TestClass 的 SEND_VAL,以便它在内存中用于下一行,实际上在 class_exists

上调用 DO_FCALL

然后您可以看到它如何处理类定义本身:

  1. ZEND_DECLARE_CLASS - 这是加载你的类定义
  2. ZEND_ADD_INTERFACE - 这会获取 JsonSerializable 并将其添加到您的类定义中
  3. ZEND_VERIFY_ABSTRACT_CLASS - 验证一切正常。

第二部分ZEND_ADD_INTERFACE似乎阻止了PHP引擎仅在其初始峰值加载类。

If you desire a more detailed discussion of how the PHP Interpreter Compiles and Executes the code in these scenarios, I suggest taking a look at @StasM answer to this question, he provides an excellent overview of it in greater depth than this answer goes.

我想我们回答了你所有的问题。

最佳实践:将您的每个类放在它自己的文件中,然后 autoload他们根据需要,如@StasM在他的回答中指出,使用合理的文件命名和自动加载策略 - 例如 PSR-0 或类似的东西。当您这样做时,您不再需要关心引擎加载它们的顺序,它会自动为您处理。

关于php - 类扩展或接口(interface)如何工作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15688642/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com