本文基于php的commit为:b18b2c8fe587321384c9423470cf97d8040b32e2
在PHP8
之前,扩展函数解析参数的时候,如果解析失败了,那么会return
,如下所示:
1 | if (zend_parse_parameters_none() == FAILURE) { |
在PHP8
后,扩展函数解析参数失败的时候,会使用RETURN_THROWS
这个宏,例如:
1 | if (c() == FAILURE) { |
我们来看看RETURN_THROWS
这个宏:
1 |
可以看出,这个宏只会去断言此时EG(exception)
不为NULL
。因为在PHP8
中,大部分不被期待的错误都应该抛异常。
但是,真正会去打印异常消息的地方是在函数zend_execute_scripts
里面:
1 | if (op_array) { |
可以看到,在执行完了我们的opcode
之后,会去判断EG(exception)
是否为NULL
,如果不为NULL
,就会调用zend_exception_error
函数,这个函数的核心是:
1 | zend_string *message = zval_get_string(GET_PROPERTY(&exception, ZEND_STR_MESSAGE)); |
(其中,exception
指向的是EG(exception)
)
可以看到,这三行会去获取EG(exception)
异常对象zend_object
的三个属性,分别是message
,file
、line
。然后组成我们的报错信息,最后通过zend_error_va
函数(实际上调用的是zend_error_cb
函数)打印出来。