构造函数用法
HP 5 允行开发者在一个类中定义一个方法作为构造函数。具有构造函数的类会在每次创建新对象时先调用此方法,所以非常适合在使用对象之前做一些初始化工作。
Note: 如果子类中定义了构造函数则不会隐式调用其父类的构造函数。要执行父类的构造函数,需要在子类的构造函数中调用 parent::__construct()。如果子类没有定义构造函数则会如同一个普通的类方法一样从父类继承(假如没有被定义为 private 的话)。
Example #1 使用新标准的构造函数
代码如下 | 复制代码 |
class BaseClass { class SubClass extends BaseClass { class OtherSubClass extends BaseClass { // In BaseClass constructor // In BaseClass constructor // In BaseClass constructor |
为了实现向后兼容性,如果 PHP 5 在类中找不到 __construct() 函数并且也没有从父类继承一个的话,它就会尝试寻找旧式的构造函数,也就是和类同名的函数。因此唯一会产生兼容性问题的情况是:类中已有一个名为 __construct() 的方法却被用于其它用途时。
与其它方法不同,当 __construct() 被与父类 __construct() 具有不同参数的方法覆盖时,PHP 不会产生一个 E_STRICT 错误信息。
自 PHP 5.3.3 起,在命名空间中,与类名同名的方法不再作为构造函数。这一改变不影响不在命名空间中的类。
Example #2 Constructors in namespaced classes
代码如下 | 复制代码 |
namespace Foo; |
建对象的时候赋初值。
代码如下 | 复制代码 |
1. //创建一个人类 2. 3. 0class Person 4. 0{ 5. //下面是人的成员属性 6. var $name; //人的名子 7. var $sex; //人的性别 8. var $age; //人的年龄 9. //定义一个构造方法参数为姓名$name、性别$sex和年龄$age 10. function __construct($name, $sex, $age) 11. { 12. //通过构造方法传进来的$name给成员属性$this->name赋初使值 13. $this->name=$name; 14. //通过构造方法传进来的$sex给成员属性$this->sex赋初使值 15. $this->sex=$sex; 16. //通过构造方法传进来的$age给成员属性$this->age赋初使值 17. $this->age=$age; 18. } 19. //这个人的说话方法 20. function say() 21. { 22. echo "我的名子叫:".$this->name." 性别:".$this->sex." 我的年龄是:".$this->age." "; 23. } 24. } 25. //通过构造方法创建3个对象$p1、p2、$p3,分别传入三个不同的实参为姓名、性别和年龄 26. $p1=new Person("张三","男", 20); 27. $p2=new Person("李四","女", 30); 28. $p3=new Person("王五","男", 40); 29. //下面访问$p1对象中的说话方法 30. $p1->say(); 31. //下面访问$p2对象中的说话方法 32. $p2->say(); 33. //下面访问$p3对象中的说话方法 34. $p3->say(); |
输出结果为:
我的名子叫:张三性别:男我的年龄是:20
我的名子叫:李四性别:女我的年龄是:30
我的名子叫:王五性别:男我的年龄是:40
构造函数的继承问题
先来看一个简单的例子:
代码如下 | 复制代码 |
class Fruit { public function __construct($name) { echo '水果'.$name.'创建了'; } }
class Apple extends Fruit { public function __construct($name) { parent::__construct($name); } }
$apple = new Apple("苹果");
// 输出 水果苹果创建了 ?> |
构造函数的继承节省的是代码的重写,而不是方法的声明,也就是说,在父类中声明的构造函数必须再在子类中声明一次,其实,这也是一个重写的过程。
PHP的构造函数继承必须满足以下条件:
当父类有构造函数的声明时,子类也必须有声明,否则会出错。
在执行父类的构造函数时,必须在子类中引用parent关键字。
如果父类有构造函数,而且子类没有构造函数,那么在子类实例化时确实会执行父类构造函数。例如,假设Employee类有如下构造函数:
代码如下 | 复制代码 |
function __construct($name){ $this->setName($name); }
echo $ceo->getName();
|
但是,如果子类也有构造函数,那么当子类实例化时,不论父类是否有构造函数,都会执行子类自己的构造函数。例如,假设除了Employee类包含上述构造函数外,CEO类也包含如下构造函数:
代码如下 | 复制代码 |
function __construct(){ echo "CEO object created!"; } |
再来实例化CEO类,以同样的方式执行getName(),这次将得到不同的输出:
CEO object created!
My name is Gonn
当遇到parent::__construct()时,PHP开始沿着父类向上搜索合适的构造函数。因为在Executive中没有找到,所以继续搜索知道Employee类,在这里找到了合适的构造函数。如果PHP在Employee类中找到构造函数,就会执行这个构造函数。如果希望既执行Employee构造函数,又执行Executive构造函数,则需要在Executive构造函数中调用parent::__construct()。
此外,还可以选择另一种方式来引用父类的构造函数。例如,假设创建新的CEO对象时,Employee和Executive的构造函数都要执行。如上述,可以在CEO的构造函数中显示地引用这些构造函数,如下:
代码如下 | 复制代码 |
Employee::__constrcut($name); Executive::__construct(); echo "CEO object created!"; |
不同php版本中构造函数继承
构造函数中的引用
PHP 4.x 的构造函数名与类名相同。
子类的构造函数名与子类名相同(废话)。
在子类里父类的构造函数不会自动执行。
要在子类里执行父类的构造函数,必须执行类似以下语句:
$this->[父类的构造函数名()]
例如:
代码如下 | 复制代码 |
class base1 class class1 extends base1 |
PHP5.x 版本:
PHP5.0 以上版本对类的功能进行了很大的扩充。类的构造函数统一命名为__construct()。
子类的构造函数名也是__construct()(也是废话)。
在子类里父类的构造函数会不会执行,分两种情况:
1,如子类不定义构造函数 __construct(),则父类的构造函数默认会被继承下来,且会自动执行。
2,如子类定义了构造函数 __construct(),因为构造函数名也是__construct(),所以子类的构造函数实际上是覆盖(override)了父类的构造函数。这时执行的是该子类的构造函数。
这时如果要在子类里执行父类的构造函数,必须执行类似以下语句:
parent::__construct();
例如:
代码如下 | 复制代码 |
class base2 class class2 extends base2 |
注意 parent::__construct(); 语句不一定必须放在子类的构造函数中。放在子类的构造函数中仅仅保证了其在子类被实例化时自动执行。
PHP4.0 和 5.0 类构造函数的兼容问题:
在 PHP5.0 以上版本里,还兼容了 4.0 版本的构造函数的定义规则。如果同时定义了4.0的构造函数和 __construct()函数,则__construct() 函数优先。
为了使类代码同时兼容 PHP4.0 和 5.0,可以采取以下的方式:
代码如下 | 复制代码 |
class class3 function class3() //for PHP4.0 $c3 = new class3; |
php构造函数中的引用的内容。
代码如下 | 复制代码 |
class Foo { function Foo($name) { global $globalref; $globalref[] = &$this; $this->setName($name); $this->echoName(); } function echoName() { echo " ",$this->name; } function setName($name) { $this->name = $name; } } ?> |
下面来检查一下用拷贝运算符 = 创建的 $bar1 和用引用运算符 =& 创建的 $bar2 有没有区别...
copy to clipboard
显然没有区别,但实际上有一个非常重要的区别:$bar1 和 $globalref[0] 并没有被引用,它们不是同一个变量。这是因为“new”默认并不返回引用,而返回一个拷贝。
代码如下 | 复制代码 |
$bar1 = new Foo('set in constructor'); $bar1->echoName(); $globalref[0]->echoName(); /* 输出: set in constructor set in constructor set in constructor */ $bar2 =& new Foo('set in constructor'); $bar2->echoName(); $globalref[1]->echoName(); /* 输出: set in constructor set in constructor set in constructor */ ?> |