PHP构造函数加载的坑
一段时间之前遇到过一个坑,CI中控制器一个方法总是会被加载两次。控制器类名叫Index,而方法名叫index。这个index方法总是会被执行两次,接下来探究一番吧。
众所周知,PHP中类的构造函数是__construct()。类被实例化的时候会执行__construct方法,如果这个类中没有那么执行其父类的__construct方法;而如果子类中有__construct方法,则不会自动执行其父类的__construct方法,如果想调用父类的构造函数则需要使用parent关键字。下面看一段代码测试。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<?php class Index { function __construct() { echo "Index __construct"; } } class IndexChild extends Index { function __construct() { echo "IndexChild __construct"; } } new IndexChild(); |
上面的代码会输出 IndexChild __construct 。如果注释掉子类的__construct方法,那么输出 Index __construct 。
除了__construct方法,在PHP4中还有另外一种构造函数,就是跟Java相同的语法:与类名同名的方法。手册里是这样写的。(这种写法在PHP7里面依然兼容。)在上面的例子中,显然就是这么写的。
1 2 3 4 5 6 7 |
<?php class Index { function Index() { echo "Index function index"; } } new Index(); |
这个会输出 Index function index 。
这样开头的问题似乎是解决了。但是现在思绪有点乱,它到底是怎么加载这几种构造函数的?那继续来探究。下面的这个例子是用来测试他们共同存在情况了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<?php class Index { function __construct() { echo "Index __construct"; } function index() { echo "Index function index"; } } class IndexChild extends Index { function __construct() { echo "IndexChild __construct"; } function indexChild() { echo "IndexChild function indexChild"; } } new IndexChild(); |
运行上面程序,输出 IndexChild __construct ,也就是说PHP5增加的__construct构造函数优先级是比同名函数要高的。
注释掉IndexChild的__construct方法,输出 IndexChild function indexChild 。
恢复原来的注释,注释掉indexChild方法,输出 Index __construct 。
这样基本就清晰了。也就是说,PHP类的构造方法是一级一级查找的,首先在本类中寻找__construct方法,不存在则寻找类同名方法,再不存在寻找父类的__construct方法,再不存在则寻找父类同名方法,再不存在寻找父类的父类……另外一个需要注意的是,PHP的类、函数名都不区分大小写,所以就算小写的同名,还是会加载。