莫名其妙的发现自动加载函数中抛出异常不会马上执行,就打算用简单的代码去重现下,还真的重现了。
文件有三个
– index.php
– a.class.php
– b.class.php
文件内容
<?php class a extends b{ public function __construct(){ parent::__construct(); echo 'in a<br>'; } }
<?php namespace test; echo 'file b.class.php'; class b{ public function __construct(){ echo 'in b<br>'; } }
<?php function __autoload($classname){ echo '__autoload 1<br>'; var_dump($classname); $classname = substr($classname, strpos($classname, '') ); if (!file_exists("{$classname}.class.php")){ echo 'throw exception<br>'; throw new Exception($classname . ' not found<br>'); } require "{$classname}.class.php"; } function __autoload2($classname){ echo '__autoload 2<br>'; var_dump($classname); $classname = substr($classname, strpos($classname, '') ); if (!file_exists("{$classname}.class.php")){ echo 'throw exception<br>'; throw new Exception($classname . ' not found<br>'); } require "{$classname}.class.php"; } spl_autoload_register('__autoload'); spl_autoload_register('__autoload2'); $a = new a();
两个__autoload函数是一样的,在发现文件不存在的时候,都会抛出异常。执行结果如下:
__autoload 1
string ‘a’ (length=1)
__autoload 1
string ‘bb’ (length=2)
throw exception
__autoload 2
string ‘bb’ (length=2)
throw exception
__autoload 2
string ‘a’ (length=1)
__autoload 1
string ‘bb’ (length=2)
throw exception
__autoload 2
string ‘bb’ (length=2)
throw exceptionFatal error: Uncaught exception ‘Exception’ with message ‘bb not found<br>’ in D:wampwwwtestindex.php on line 18
Exception: bb not found<br> in D:wampwwwtestindex.php on line 18
仔细看看结果,各种理解不能。第5行的时候,抛出异常,被忽略了,没抛出。然后,为什么A2(__autoload2)又加载一遍a呢?然后,A1(__autoload)又加载了一遍bb,至此,A1已经加载两次bb了。然后,A1又加载了一遍bb。最后才抛出异常,看行号是A2函数抛出来的。
然后,上边有看到A2在A1已经加载过一次a的时候,又加载了一次a。而a文件中明显不能被require两次啊!否则会报class重复定义的错误的啊!!!可结果呢,没报。。
这个其实是说明了另外一个问题:如果PHP没完成定义类的所有步骤,就不算定义了一个类。比如,a的定义就需要把继承的父类找到,在找父类的时候失败了,a就算没定义成功。所以,来回定义a都是可以的,因为你没定义成功嘛。。。。
然后,继续猜测如上所有步骤:
A1接到加载a的通知,找到a.class.php文件并包含,发现bb找不到,A1又去找bb,发现找不到,抛出异常,因为存在两个自动加载函数,第一个找不到的时候,第二个上,所以这个时候A2去找bb,同样找不到,抛出异常。此时,你可能会感觉这不结束了么?两个自动加载函数都找不到的类,并且都抛出异常了,该结束了。可实际上,类a的自动加载并没有成功(我是这么理解的,可能不对,后边说),A2会再去尝试加载一次类a,然后,同样发现类bb,这个时候,针对bb的自动加载还是从A1开始,然后A2,最终,A2也没能找到bb。所以,加载类a的这个过程终结了,异常憋了半天终于抛出来来。
上边说,A2在找不到bb的时候是因为类a的加载并没有完成,所以才没抛出异常的。我就尝试修改了下测试代码验证这个问题。
<?php class a extends b{ public function __construct(){ parent::__construct(); echo 'in a<br>'; } }
<?php
<?php function __autoload($classname){ echo '__autoload 1<br>'; var_dump($classname); $classname = substr($classname, strpos($classname, '') ); if (!file_exists("{$classname}.class.php")){ echo 'throw exception<br>'; throw new Exception($classname . ' not found<br>'); } echo 'include ', $classname, '<br>'; require "{$classname}.class.php"; } function __autoload2($classname){ echo '__autoload 2<br>'; var_dump($classname); $classname = substr($classname, strpos($classname, '') ); if (!file_exists("{$classname}.class.php")){ echo 'throw exception<br>'; throw new Exception($classname . ' not found<br>'); } echo 'include ', $classname, '<br>'; require "{$classname}.class.php"; } spl_autoload_register('__autoload'); spl_autoload_register('__autoload2'); $a = new a();
结果如下:
__autoload 1
string ‘a’ (length=1)
include a
__autoload 1
string ‘b’ (length=1)
include b
__autoload 2
string ‘b’ (length=1)
include bFatal error: Class ‘b’ not found in D:wampwwwtesta.class.php on line 2
可以看到,跟我最开始想的结果一样,当两个自动加载函数都找不到一个类的时侯,那么就报错。然后,我想了想又改了下index.php。接着上代码:
<?php function __autoload($classname){ echo '__autoload 1<br>'; var_dump($classname); $classname = substr($classname, strpos($classname, '') ); if (!file_exists("{$classname}.class.php")){ echo 'throw exception<br>'; throw new Exception($classname . ' not found<br>'); } echo 'include ', $classname, '<br>'; require "{$classname}.class.php"; if (!class_exists($classname, false)){ echo 'throw exception2<br>'; throw new Exception($classname . ' not found2<br>'); } } function __autoload2($classname){ echo '__autoload 2<br>'; var_dump($classname); $classname = substr($classname, strpos($classname, '') ); if (!file_exists("{$classname}.class.php")){ echo 'throw exception<br>'; throw new Exception($classname . ' not found<br>'); } echo 'include ', $classname, '<br>'; require "{$classname}.class.php"; if (!class_exists($classname, false)){ echo 'throw exception2<br>'; throw new Exception($classname . ' not found2<br>'); } } spl_autoload_register('__autoload'); spl_autoload_register('__autoload2'); $a = new a();
我在自动加载函数后边判断了下类是否存在,不存在还抛出异常。
结果如下:
__autoload 1
string ‘a’ (length=1)
include a
__autoload 1
string ‘b’ (length=1)
include b
throw exception2
__autoload 2
string ‘b’ (length=1)
include b
throw exception2
__autoload 2
string ‘a’ (length=1)
include a
__autoload 1
string ‘b’ (length=1)
include b
throw exception2
__autoload 2
string ‘b’ (length=1)
include b
throw exception2Fatal error: Uncaught exception ‘Exception’ with message ‘b not found2<br>’ in D:wampwwwtestindex.php on line 29
Exception: b not found2<br> in D:wampwwwtestindex.php on line 29
结果又跟版本1一样了。。。我就又改了下代码:
<?php function __autoload($classname){ echo '__autoload 1<br>'; var_dump($classname); $classname = substr($classname, strpos($classname, '') ); if (!file_exists("{$classname}.class.php")){ echo 'throw exception<br>'; throw new Exception($classname . ' not found<br>'); } echo 'include ', $classname, '<br>'; require "{$classname}.class.php"; if (!class_exists($classname, false)){ echo 'throw exception2<br>'; // throw new Exception($classname . ' not found2<br>'); } } function __autoload2($classname){ echo '__autoload 2<br>'; var_dump($classname); $classname = substr($classname, strpos($classname, '') ); if (!file_exists("{$classname}.class.php")){ echo 'throw exception<br>'; throw new Exception($classname . ' not found<br>'); } echo 'include ', $classname, '<br>'; require "{$classname}.class.php"; if (!class_exists($classname, false)){ echo 'throw exception2<br>'; // throw new Exception($classname . ' not found2<br>'); } } spl_autoload_register('__autoload'); spl_autoload_register('__autoload2'); $a = new a();
就是把抛出异常的代码注释掉了。结果如下:
__autoload 1
string ‘a’ (length=1)
include a
__autoload 1
string ‘b’ (length=1)
include b
throw exception2
__autoload 2
string ‘b’ (length=1)
include b
throw exception2Fatal error: Class ‘b’ not found in D:wampwwwtesta.class.php on line 2
可以看出autoload在处理函数中是否有抛出异常上跟其他函数是不一样的。而官网也没看到相关说明啊。。。
最终,我只能猜测:
存在多个autuload函数的时候,每加载一个类,只要前边的函数没执行完(包括最后抛出异常),那么就算此类没加载成功,就会有后边的autoload函数继续加载。