构造方法是用来初始化成员变量的,当我们实例化对象时,会自动执行构造方法。那么当使用继承时,在构造方法方面我们应该注意什么呢?
注意:在PHP的继承中,构造方法有很多的坑,需要我们去发现。
我们改造上节课中的代码,还是汽车,卡车,公交车,我们把构造方法添加上。
<?php
/**
* 汽车类
*/
class Car
{
public $wheel; //汽车轮子
function __construct($wheel)
{
$this->wheel = $wheel;
}
public function run()
{
echo '能跑';
}
public function stop()
{
echo '能刹车';
}
}
/**
* 卡车类,继承了汽车类
*/
class Truck extends Car
{
public $load; //载货量
}
/**
* 公交车类,继承汽车类
*/
class Bus extends Car
{
public $peples; //载客量
public function say(){
echo '报站';
}
}
$t = new Truck();
$t->wheel = 12; //卡车12个轮子
$t->load = '20T'; //载重20吨
$t->run(); //卡车在行驶中
$b = new Bus();
$b->wheel = 6; //公交车6个轮子
$b->peples = '50人'; //载客50人
$b->say(); //在报站
运行上面的代码,会报告很多错误。
主要错误是说:实例化truck对象和bus对象时,执行了构造方法,但缺少了一个参数。
我们分析一下:
在父类car中,我们定义了构造方法。
在子类truck和bus中,我们没有定义构造方法。
当实例化子类的对象时,系统会自动执行父类的构造方法。
因为父类的构造方法有一个参数,而我们实例化子类对象时,没有传递参数,就发生了错误。
下面我们重新改写一下代码。
<?php
/**
* 汽车类
*/
class Car
{
public $wheel; //汽车轮子
function __construct($wheel)
{
$this->wheel = $wheel;
}
public function run()
{
echo '能跑';
}
public function stop()
{
echo '能刹车';
}
}
/**
* 卡车类,继承了汽车类
*/
class Truck extends Car
{
public $load; //载货量
}
/**
* 公交车类,继承汽车类
*/
class Bus extends Car
{
public $peples; //载客量
public function say(){
echo '报站';
}
}
$t = new Truck(12);//传递参数
printf("卡车有%d个轮子",$t->wheel);
echo '<br>';
$b = new Bus(6);//传递参数
printf("公交车有%d个轮子",$t->wheel);
运行结果如下:
如果子类有自己的构造方法,结果又会如何呢?
<?php
/**
* 汽车类
*/
class Car
{
public $wheel; //汽车轮子
function __construct($wheel)
{
$this->wheel = $wheel;
}
public function run()
{
echo '能跑';
}
public function stop()
{
echo '能刹车';
}
}
/**
* 卡车类,继承了汽车类
*/
class Truck extends Car
{
public $load; //载货量
function __construct()
{
}
}
/**
* 公交车类,继承汽车类
*/
class Bus extends Car
{
public $peples; //载客量
function __construct()
{
}
public function say(){
echo '报站';
}
}
$t = new Truck(12);//传递参数
printf("卡车有%d个轮子",$t->wheel);
echo '<br>';
$b = new Bus(6);//传递参数
printf("公交车有%d个轮子",$t->wheel);
运行结果如下:
分析一下原因:
当子类有自己的构造方法时,实例化子类的对象,就会执行子类的构造方法,不会执行父类的构造方法。这是PHP与其它编程语言不同之处。
子类的构造方法没有参数,而我们实例化子类对象时传递了一个参数,为什么没有报错呢?
在PHP中,调用函数或执行方法时,可以多传递参数,不可以少传递参数。多出来的参数在传递时是无效的,不会报错。
总结:
子类继承父类时,子类没有构造方法,实例化子类对象时,会执行父类的构造方法。子类如果有自己的构造方法,实例化子类对象时,只会自动执行子类自己的构造方法。
那么如何实现:实例化子类对象时,既要执行子类的构造方法,又要执行父类的构造方法呢?
参见 下面的代码,我们继续改造代码。
<?php
/**
* 汽车类
*/
class Car
{
public $wheel; //汽车轮子
function __construct($wheel)
{
$this->wheel = $wheel;
}
public function run()
{
echo '能跑';
}
public function stop()
{
echo '能刹车';
}
}
/**
* 卡车类,继承了汽车类
*/
class Truck extends Car
{
public $load; //载货量
function __construct($wheel)
{
//调用父类的构造方法
parent::__construct($wheel);
}
}
/**
* 公交车类,继承汽车类
*/
class Bus extends Car
{
public $peples; //载客量
function __construct($wheel)
{
//调用父类的构造方法
parent::__construct($wheel);
}
public function say(){
echo '报站';
}
}
$t = new Truck(12);//传递参数
printf("卡车有%d个轮子",$t->wheel);
echo '<br>';
$b = new Bus(6);//传递参数
printf("公交车有%d个轮子",$t->wheel);
在子类的构造方法中,使用 parent::__construct($wheel); 主动调用父类的构造方法。
当然,子类的构造方法也可以有多个参数:
<?php
/**
* 汽车类
*/
class Car
{
public $wheel; //汽车轮子
function __construct($wheel)
{
$this->wheel = $wheel;
}
public function run()
{
echo '能跑';
}
public function stop()
{
echo '能刹车';
}
}
/**
* 卡车类,继承了汽车类
*/
class Truck extends Car
{
public $load; //载货量
function __construct($wheel,$load)
{
//调用父类的构造方法
parent::__construct($wheel);
$this->load = $load;
}
}
/**
* 公交车类,继承汽车类
*/
class Bus extends Car
{
public $persons; //载客量
function __construct($wheel,$peples)
{
//调用父类的构造方法
parent::__construct($wheel);
$this->persons = $peples;
}
public function say(){
echo '报站';
}
}
$t = new Truck(12,20);//传递两个参数
printf("卡车有%d个轮子,载重%d吨",$t->wheel,$t->load);
echo '<br>';
$b = new Bus(6,50);//传递两个参数
printf("公交车有%d个轮子,载客%d人",$t->wheel,$b->persons);
因为子类的构造方法有两个参数,所以当我们实例化子类对象时,必须传递两个参数。
好了,PHP中有关继承时的构造方法,我们已经把“坑”填平了,做为初学者,一定牢记。