本文基于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函数)打印出来。