Press "Enter" to skip to content

深入理解PHP原理之错误抑制与内嵌HTML

PHP支持内嵌HTML的, 那么对于PHP文件中, PHP标签外的HTML会怎么处理呢? 它和直接输出HTML有什么区别么?
PHP提供了一个错误抑制符'@', 它是通过什么方式来阻止错误输出呢? 我又该在什么时候使用它呢?
这是这俩天一些网友提到的共同问题, 今天就索性整体回答下, 备后来人翻阅.

PHP文件内嵌HTML的处理方式

在PHP中, 所有在标签外的字符, 在词法分析过程中, 都会翻译成T_INLINE_HTML token, 在语法分析的时候, 所有的T_INLIE_HTML都会被分配ZEND_ECHO输出.
也就是说:

<?php
while($con) {
?>
laruence
<?php
 }
?>

会生成一条OPLINE: T_ECHO, 而操作数是"laruence";
就结果来说, 上面的代码, 其实和下面的结果一样:

<?php
 while($con) {
   echo "laruence";
 }
?>

但有一个要注意的地方是, 对于PHP标签外的字符, 在词法分析过程中, 都会以400个字符为单位切分, 比如:

<?php
    if(1) {
?>
laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence  laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence laruence
 <?php
    }
?>

上面的代码中, 标签外有531个字符(包含空格回车), 会被分成俩条T_INLINE_HTML输出.

错误抑制符

我们知道,在PHP中,可以通过错误抑制符来静默错误提示, 那么它是通过什么方式呢?
在语法分析的过程中, 对于:

<?php
	@include('file');
?>

会分别在include语句前后插入俩条Opline(操作), 这俩个操作分别做:

1. 保存当前的error_reporting值, 并设置error_reporting(0); //关闭错误输出
2. 恢复之前保存的error_reporting值.

也就是说, 其实上面的代码, 和下面的代码类似:

$old = error_reporting(0);
include('file');
error_reporting($old);

另外, 讲一句题外话:"什么时候才应用错误抑制呢?", 我个人建议, 就是如果这条语句出错了对你影响不大, 你也不关心这个错误是什么, 你也不会安排额外的逻辑来处理这种错误, 那么你可以使用错误抑制. 否则, 请你使用额外的逻辑来判断错误.

24 Comments

  1. superfighters
    superfighters November 5, 2018

    Very nice I really like this article.

  2. Tish
    Tish May 4, 2016

    Felt so hopeless looking for answers to my quionests…until now.

  3. […] 深入理解PHP原理之变量分离/引用(Variables Separation) 07 Nov 08 PHP的GET/POST等大变量生成过程 07 Nov 08 深入理解PHP原理之文件上传 27 Jul 09 深入理解PHP原理之错误抑制与内嵌HTM […]

  4. […] if(true) { } else { } 11. 尽量少用@错误抑制符 如下代码: @func(); 就相当于(参见深入理解PHP原理之错误抑制与内嵌HTML): $report = error_reporting(0); func(); error_reporting($report); 另外错误抑制符号, […]

  5. Anonymous
    Anonymous January 15, 2010

    @kimjxie() @laruence()
    哈哈哈吼吼吼
    我觉得存在就是有道理的
    不过catch那种机制不知道是不是会好一些

  6. laruence
    laruence October 27, 2009

    @kimjxie 呵呵, @比起写error_reporting来说方便很多, 也能精确选择沉默点. 本质上他们的作用原理一样.
    我的出发点也是说, 不能依靠@来掩盖错误, 只是规避一些已知的,不关心的错误”我个人建议, 就是如果这条语句出错了对你影响不大, 你也不关心这个错误是什么, 你也不会安排额外的逻辑来处理这种错误, 那么你可以使用错误抑制. 否则, 请你使用额外的逻辑来判断错误”

  7. kimjxie
    kimjxie October 27, 2009

    好像搞错讨论点了. =,=
    你提出有些时候必须使用@,不管yii还是网络中端,到最后都可以通过error_reporting来完成.
    既然有选择,那为什么要用一个自己不能控制的而且会给以后工作埋下隐患的方式呢?
    就如我前面说的不提出使用@的两个原因中,主要是第一条.
    何况@也不是说所有的错误都可以抑制.

  8. laruence
    laruence October 26, 2009

    @kimjxie 不是说Yii的问题, require一个不存在的问题就会导致warning, 而auto load和插件化设计必然会可能出现require一个不存在的类文件的情况. 这个不是代码规范不规范的问题. 再比如, fsockopen打开一个host, 如果这个host突然down了,也会引发一个warning..

  9. kimjxie
    kimjxie October 26, 2009

    @laruence
    出现Notice和warning是因为代码不符合语言或解析器的规范要求.这个是代码的问题需要自身进行改进,而不是以鸵鸟方式把这个问题抛在脑后.语言的灵活性不是体现在对不良代码的包容上.
    当然,对于我等懒人,@可以作为临时解决方案,:P,但终究还是要修改完善的.
    yii居然这样搞阿 -,-

  10. laruence
    laruence October 26, 2009

    比如,对于一些零容忍的框架,比如YII,不能有任何的Notice或者warning, 那么在auto load机制require一个外部类的时候,你必须使用错误抑制来应对这个类不存在的情况. 等等

  11. 米渣
    米渣 October 26, 2009

    @laruence 什么时候是必须的呢?

  12. laruence
    laruence October 24, 2009

    @kimjxie 有的时候, 是必须要使用错误抑制的…

  13. kimjxie
    kimjxie October 24, 2009

    相反的,应该避免使用@错误抑制符
    1,会造成调试维护上的黑洞,一旦有错误发生,而不知道错误信息是很让人抓瞎的事
    2,使用@后,虽然php代码来这个过程简单,但实际opcode的操作还是比较繁琐的,影响效率是当然的

  14. Edward
    Edward September 14, 2009

    顶了,原来错误抑制是用这个原理啊,我还以为什么深不可测的原理呢!

Comments are closed.