代码之家  ›  专栏  ›  技术社区  ›  mario

你注意到了吗?==E_DEBUG,避免isset()和@with更复杂的错误处理程序

  •  11
  • mario  · 技术社区  · 14 年前

    isset() 在应用程序逻辑中,并保留查看调试消息的能力(E_NOTICE) 什么时候

    先假设:EúNOTICE不是一个错误,它是一个误称,实际上应该是EúDEBUG。然而,对于未设置的变量(PHP仍然是一种脚本语言),这是正确的,但是一些文件系统函数等也会抛出它们。因此,我们希望 发展 上面写着Eúu通知。

    introduce isset() 以及贯穿整个应用程序逻辑的@。isset/empty确实有许多有效的用例,但总的来说 实际上会妨碍调试。

    这就是我目前使用错误报告bookmarklet和哑开/关开关的原因:

    // javascript:(function(){document.cookie=(document.cookie.match(/error_reporting=1/)?'error_reporting=0':'error_reporting=1')})()
    
    if (($_SERVER["REMOTE_ADDR"] == "127.0.0.1")
        and $_COOKIE["error_reporting"])
    {
        error_reporting(E_ALL|E_STRICT);
    }
    else {/* less */}
    

    然而,这仍然让我有一个问题,即一旦启用,就有太多的通知要搜索。作为解决方法,我可以使用@error suppression操作符。与isset()不同的是,它不会完全终止调试选项,因为自定义错误处理程序仍然可以接收被禁止的E_通知。所以分开可能会有帮助 预期 潜在问题的调试通知。

    然而,这同样令人不满意。这就是问题所在。是否有人使用或知道更复杂的PHP错误处理程序。我在想象:

    • 以及AJAX什么不允许客户端检查和抑制
    • 同时还保存了一个筛选列表 经核准的 " 通知或警告。

    当然,某些框架必须已经有了这样的用户错误处理程序。

    • 完全的EúNOTICE抑制确实不理想。
    • 通缉犯。只是少一点。默认情况下,请突出显示我可能关心的内容,而不是预期的内容。
    • 如果我不跑?order=参数,一个预期的通知occours。这是意料之中的,我不需要知道不止一次。
    • 还要认识到这是关于普通PHP表单处理语义适用的用例,而不是必须严格的应用程序区域。

    9 回复  |  直到 8 年前
        1
  •  3
  •   mario    10 年前

    如果您等待PHP 7,就可以访问 null coalesce ternary 运算符,除了存在最酷的操作符名(我命名下一个孩子“NULL CONESCE”)将允许您这样做:

    $var = $some_array[$some_value] ?? "default value";
    

    $var = isset( $some_array[$some_value] ) ? $some_array[$some_value] : "default_value";
    
        2
  •  9
  •   staticsan    14 年前

    开发一个大型的PHP应用程序是可能的,它永远不会发出任何E_通知。你所要做的就是避免所有可以发出通知的情况,其中绝大多数是未初始化的变量和非Exxistar数组密钥。不幸的是,这与你希望避免 isset() -并通过扩展 array_key_exists() -因为他们是为解决这个问题而设计的。

    最多,您可以通过仔细构建框架来最小化它们的使用。这通常意味着(例如)输入层被告知 GET

    与其他语言不同,PHP区分一个不存在的变量和包含一个通常为“空”的值(通常)。 null ). 它可能是早期版本的一个设计工件,但它仍然存在,因此您不能真正避免它。

        3
  •  6
  •   István Ujj-Mészáros    14 年前

    isset() $_GET $_SERVER 外部 控制我的申请。当我没有时间写一个合适的面向对象的解决方案来避免它的时候,我在其他一些情况下使用它,但是我相信在大多数地方,即使不是所有的地方,也可以避免它。例如,最好使用类而不是关联数组,这样就不需要检查数组密钥的存在。

    我的建议是:

    • Avoid using the @ operator .
    • 使用 Xdebug 堆栈跟踪 在异常情况下(您可以将其配置为打印出每个方法参数和每个局部变量( xdebug.collect_params=4 xdebug.show_local_vars=on @ xdebug.scream=1 配置值。您可以使用Xdebug 以及代码覆盖率分析。它是 必须的
    • 为了调试,我还使用 FirePHP ,因为它与 Firebug ,并能够将消息打印到 Firebug console ,所以它可以用于 AJAX调试
    • 用一个 自定义错误处理程序 ,您可以捕获和筛选任何错误和警告,并将其记录到文件中或使用firphep显示,或者可以使用 jGrowl Gritter 在网页上很好地显示它们。

    PHP manual :

    <?php
    //error_reporting(0);
    set_error_handler("errorHandler");
    
    function errorHandler($errno, $errstr, $errfile, $errline)
    {
        echo "errorHandler()<br />\n";
    
        // filter out getImageSize() function with non existent files (because I'am avoiding using file_exists(), which is a costly operation)
        if ( mb_stripos($errstr, 'getimagesize') !== false )
            return true;
    
        // filter out filesize() function with non existent files
        if ( mb_stripos($errstr, 'filesize') !== false )
            return true;
    
        // consoleWriter is my class which sends the messages with FirePHP
        if (class_exists('consoleWriter'))
            consoleWriter::debug(array('errno'=>$errno, 'errstr'=>$errstr, 'errfile'=>$errfile, 'errline'=>$errline, 'trace'=>debug_backtrace()), "errorHandler");
    
        switch ($errno) {
        case E_USER_ERROR:
            $out .= "<b>FATAL_ERROR</b> <i>$errno</i> $errstr<br />\n";
            $out .= "Fatal error on line $errline in file $errfile";
            echo "</script>$out";   // if we were in a script tag, then the print is not visible without this
            //writeErrorLog($out);
    
            echo "<pre>";
            var_export(debug_backtrace());
            echo "</pre>";
    
            exit(1);
            break;
    
        case E_USER_WARNING:
            $out .= "<b>WARNING</b> <i>$errno</i> $errstr<br />\n";
            $out .= "On line $errline in file $errfile<br />\n";
            break;
    
        case E_USER_NOTICE:
            $out .= "<b>NOTICE</b> <i>$errno</i> $errstr<br />\n";
            $out .= "On line $errline in file $errfile<br />\n";
            break;
    
        default:
            $out .= "<b>Unknown</b> <i>$errno</i> $errstr<br />\n";
            $out .= "On line $errline in file $errfile<br />\n";
            break;
        }
    
        if (!class_exists('consoleWriter'))
            echo $out;
    
        //writeErrorLog($out);
        //addJGrowlMessage($out);
    
        // Don't execute PHP internal error handler
        return true;
    }
    
    function testNotice($a)
    {
        echo $a;
    }
    testNotice();
    

    还有一个建议是 not to use the closing ?> tag 只在php文件的末尾,因为它会导致 headers already sent 默认情况下禁用输出缓冲的配置错误。

        4
  •  2
  •   ajreal    14 年前

    xdebug - http://www.xdebug.org/docs/stack_trace

    很多 isset 检查不会伤害你,

    实际上,它鼓励在使用之前声明变量

        5
  •  2
  •   PazsitZ    14 年前

    但写一个 user-defined error handler 使用debug_backtrace使用regexp对E_NOTICE(8)进行排序。

        7
  •  2
  •   Mike    14 年前

    下面是当我遇到这个让代码无法读取的问题时所做的操作:

    /**
     * Safely index a possibly incomplete array without a php "undefined index" warning.
     * @param <type> $array
     * @param <type> $index
     * @return <type> null, or the value in the index (possibly null)
     */
    function safeindex($array, $index) {
      if (!is_array($array)) return null;
      return (isset($array[$index])) ? $array[$index] : null;
    }
    
    // this might generate a warning
    $configMenus = $config['menus'];  
    
    // WTF are you talking about!!  16 punctuation marks!!!
    $configMenus = (isset($config['menus']) ? $config['menus'] : null;
    
    // First-time awkward, but readible
    $configMenus = safeindex($config, 'menus');
    

    在这里交叉发布这个答案。这有助于垃圾邮件检查吗?

        8
  •  1
  •   Cfreak    14 年前

    最好的避免方法 isset() 在我看来,在使用变量之前先定义它们。我不喜欢 与其说是因为它丑陋,不如说是因为它促进了糟糕的编程实践。

    至于错误处理本身,我将所有这些信息输出到服务器日志中。我也用 php -l 在命令行上进行语法检查,然后再手动操作程序。默认情况下,我会为用户生成漂亮的消息。

    编辑: @马里奥-我对你的评论反应太长了:-)。我不提倡定义类型或使用某种严格的格式,比如Java或C,我只是提倡在使用的上下文中声明变量。( $foo = null;

    我认为在很多情况下,这更多的是全局变量的问题,特别是用于获取和发布数据的超全局变量。我真的希望PHP能够去掉超全局变量,而使用一个类来获取输入数据。像这样的事情(非常简单,但是嘿,你想要一些具体的东西:)

    <?php
    class PostData {
         private $data;
    
         public function __construct() {
              $this->data = $_POST;
              unset($_POST);
         }
    
         public function param($name, $value = null) {
              if( $value !== null ) {
                   $this->data[$name] = $value;
              }
    
              if( isset( $this->data[$name] ) ) {
                   return $this->data[$name];
              }
              return null;
          }
    }
    ?>  
    

    包含类,然后您可以从 param() 伊塞特() (已经是了)。

        9
  •  1
  •   mario    10 年前

    这是一个过时的答案,但我最初使用了一个灵活的日志调度器,当时, https://github.com/grosser/errorhandler

    不管怎样,我同时在用 $_GET->int["input"] wrapper

    对于另一个项目,我甚至使用了一个预处理器宏 IFSET@($var)