欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Zend Framework的缺陷(连载之1)

程序员文章站 2022-05-11 10:15:29
...
Zend Framework的缺陷
从现在开始,将抽空发一个长篇的找抽的文章。专门谈一谈PHP官方的Zend Framework的一些设计缺陷。欢迎大家拍砖!
(1)Exception类的缺陷:
Zend Framework中的Exception看起来设计得非常精巧,实质上,那是由于它了解PHP的源码,强行为了适应php5.2和php5.3而写出的这样的怪胎。
其根本目的,是为了能够向用户提供链式的Exception。然而,可悲的是:此类中,并没有提供一个函数,能够直接向用户提供链式的Exception信息。
也许,很多衩学者不解,链式的Exception信息有什么用处?
我们还是从错误与异常的处理的基本知识着眼讲解一下:
  * 什么时间用 @
  * 什么时间用 return FALSE
  * 什么时间用 exit die
  * 什么时间用 trigger_error
  * 什么时间用 throw 抛出异常
return FALSE 只是在程序无论结果如何,用户都能清楚,不需要了解错误详情,并且,也不需要对程序进行任何处理的情况下使用当程序能够直接退出,并且程序是在调试状态时,则可以用exit和die,因为,exit和die能够简单地向输出目标,比如浏览器页面,或控制台,或重定向后的文件输出你所指定的信息。但exit和die没有抛出错误或异常,所以,你无法通过集中重定向到格式化的页面。@本质是封住相关的错误与警告信息。最终使代码能够平安地return FALSE。
trigger_error 可以使用的情况则是,能够确定,这个地方是在运行时绝对不能错的,程序一但调试好,那么,也就不会再出错的, trigger_error 也是在程序调试与正式运行时,向用户报告信息。trigger_error 目标是程序必须中断。而不能继续。并且,可以被errhandle程序捕获。不同于exit和die,它们是直接退出。
exit和die是在正式使用时,是程序需要直接退出,与错误无关。
用throw 抛出异常,则是你这一段程序中出现的问题交给用户处理,由用户来决定,程序是否继续的一种方法。当然,在此情况下,也就存在了另一种危险。那就是,如果用户不清楚哪里会抛出了异常,那么,有异常就不能被捕获,造成真实的错误中断。
用throw 抛出异常时,如果程序中使用set_exception_handler,则与程序中使用set_error_handler的结果一样,会把异常集中处理。但通常是,异常是要分开处理的。而错误则是要集中处理的。 有监于这一点,用户自定义异常类是很有必要的。
在处理异常之时,我们直接判断类型,那是最方便的。所以,一般情况下,是定义不同类型的异常 类,然后,可以直接用instanceof判断。但是,这虽然方便,却有另外一个问题,那就是我们需要定义相当多的类,以用于我们不同情况下的需要。
异常是否需要支持链式异常?链式异常的好处是可以知道异常的来龙去脉,为什么要了解这些?
一旦有所了解,就能够清楚,我们在编码时,在哪些地方必须要使用异常捕获管理。这样,代码就不会留下后患。但正式支持链式异常也只有php5.30才开始,所以,低于这样的版本需要框架提供代码来实现。因为开发者正常查看框架的源码的机会比较少。甚致也不会遵循代码示例。可见,链式异常最大的好处是能够让用户了解并清楚异常的来龙去脉。

从上面这些,我们可以发现,如果我们能够向用户提供链式异常的详细信息才是最为重要的。
如何提供呢?
php5.2的中文手册中有这么一个用户注解。代码虽较为初级,但却实现了实际的需求。
/* Author : Romain Boisnard */
/* Liscenced under the LGPL GNU Lesser General Public Liscence, report the actual liscence for details.

/* LinkedException */
// Java-like exception with a cause

class LinkedException extends Exception {
    private $cause;
    
    function __construct($_message = null, $_code = 0, Exception $_cause = null) {
        parent::__construct($_message, $_code);
        $this->cause = $_cause;
    }
    
    public function getCause() {
        return $this->cause;
    }
    
    public function getStackTrace() {
        if ($this->cause !== null) {
            $arr = array();
            $trace = $this->getTrace();
            array_push($arr, $trace[0]);
            unset($trace);
            if (get_class($this->cause) == "LinkedException") {
                foreach ($this->cause->getStackTrace() as $key => $trace) {
                    array_push($arr, $trace);
                }
            }
            else {
                foreach ($this->cause->getTrace() as $key => $trace) {
                    array_push($arr, $trace);
                }
            }
            return $arr;
        }
        else {
            return $this->getTrace();
        }
    }
    
    public function showStackTrace() {
        $htmldoc = "<p style=\"font-family: monospace; border: solid 1px #000000\"><span style=\"font-weight: bold; color: #000000;\">An exception was thrown :<br/></span>";
        $htmldoc.= "Exception code : $this->code<br/>";
        $htmldoc.= "Exception message : $this->message<br/>";
        $htmldoc.= "<span style=\"color: #0000FF;\">";
        $i = 0;
        foreach ($this->getStackTrace() as $key => $trace) {
            $htmldoc.= $this->showTrace($trace, $i);
            $i++;
        }
        $htmldoc.= "#$i {main}<br/>";
        unset($i);
        $htmldoc.= "</span></p>";
        return $htmldoc;
    }
    
    private function showTrace($_trace, $_i) {
        $htmldoc = "#$_i ";
        if (array_key_exists("file",$_trace)) {
            $htmldoc.= $_trace["file"];
        }
        if (array_key_exists("line",$_trace)) {
            $htmldoc.= "(".$_trace["line"]."): ";
        }
        if (array_key_exists("class",$_trace) && array_key_exists("type",$_trace)) {
            $htmldoc.= $_trace["class"].$_trace["type"];
        }
        if (array_key_exists("function",$_trace)) {
            $htmldoc.= $_trace["function"]."(";
            if (array_key_exists("args",$_trace)) {
                if (count($_trace["args"]) > 0) {
                    $args = $_trace["args"];
                    $type = gettype($args[0]);
                    $value = $args[0];
                    unset($args);
                    if ($type == "boolean") {
                        if ($value) {
                            $htmldoc.= "true";
                        }
                        else {
                            $htmldoc.= "false";
                        }
                    }
                    elseif ($type == "integer" || $type == "double") {
                        if (settype($value, "string")) {
                            if (strlen($value) <= 20) {
                                $htmldoc.= $value;
                            }
                            else {
                                $htmldoc.= substr($value,0,17)."...";
                            }
                        }
                        else {
                            if ($type == "integer" ) {
                                $htmldoc.= "? integer ?";
                            }
                            else {
                                $htmldoc.= "? double or float ?";
                            }
                        }
                    }
                    elseif ($type == "string") {
                        if (strlen($value) <= 18) {
                            $htmldoc.= "'$value'";
                        }
                        else {
                            $htmldoc.= "'".substr($value,0,15)."...'";
                        }
                    }
                    elseif ($type == "array") {
                        $htmldoc.= "Array";
                    }
                    elseif ($type == "object") {
                        $htmldoc.= "Object";
                    }
                    elseif ($type == "resource") {
                        $htmldoc.= "Resource";
                    }
                    elseif ($type == "NULL") {
                        $htmldoc.= "null";
                    }
                    elseif ($type == "unknown type") {
                        $htmldoc.= "? unknown type ?";
                    }
                    unset($type);
                    unset($value);
                }
                if (count($_trace["args"]) > 1) {
                    $htmldoc.= ",...";
                }
            }            
            $htmldoc.= ")<br/>";
        }
        return $htmldoc;
    }
}