类与面向对象基础(三)
一、继承
可以使一个类继承并拥有另一个已经存在类的成员属性和方法,被继承的类称为父类或基类,继承类为子类。通过extends关键字实现继承关系。通俗来说,要有继承就得有一个“根源”,这“根源”你可能想像你以后生了儿子或者女儿,他们会从你这里得到一些“东西(属性和方法)”,这样你的“后代”就是持有你(根源)所有的一些特征了。
产生“根源”类(父类或者基类)
语法:class father{
}
产生“后代”(子类)
语法:class son extends father{
}
PHP extends类继承示例代码:
class father{
protected $name;
function __construct($name){ //构造函数
$this->name=$name;
}
function work(){
echo "{$this->name}我在工作;
}
function __destruct(){} //析构函数
}
class son extends father{ //继承父类
function play(){
echo "{$this->name}我在玩游戏;
}
}
$my_father=new father(“爸爸”); //创建父类对象
$my_father->work();
$my_son=new son(“儿子”);
$my_son->work();
$my_son->play();
解析:在父类father里,我们定义了一般的属性和方法,然后定义子类。你可能发现在子类里内是没有构造函数和析构函数的,因为子类是继承了父类的所有方法,所以可以调用$my_son->work(); 这就是PHP类的继承了。另外要注意:PHP不能多层继承,如:class A extends B extends C,这样的继承在PHP中是无效的,PHP里只有单继承,不能多继承,需要其他办法变相“实现”多继承。
二、多态
多态是指在面向对象中能够根据使用类的上下文来重新定义或改变类的性质和行为。
PHP不支持重载实现多态,但是PHP可以变向的实现多态效果。如下:
class a
{ function test($i)
{ // $i可以是任何类型的变量 print_r $i; } }
上例,可以看出由于PHP是弱类型语言,所以$i可以是任何类型的变量,这样一个函数就可以实现如java等强类型语言中靠改变参数类型重载方法的多态形式。
这种形式比JAVA的参数类型重载更便捷高效,但也存在问题,如下:
<?php
/**
教师类有一个drawPolygon()方法需要一个Polygon类,用来画多边形,此方法内部调用多边形的draw()方法,但由于弱类型,我们可以传入Circle类,就会调用Circle类的draw方法,这就事与愿违了。甚至可以传入阿猫、阿狗类,如果这些类没有draw()方法还会报错。
*/
class Teacher{
function drawPolygon($polygon){
$polygon->draw();
}
}
class Polygon{
function draw(){
echo "draw a polygon";
}
}
class Circle{
function draw(){
echo "draw a circle";
}
}
?>
可以看出这样灵活的多态,需要一些控制,在PHP5.3以后可以对参数做类型限制,如下:
// 仿java,在变量参数前加一个限制类名 function drawPolygon(Polygon $polygon)
{ $polygon->draw(); }
这样就限制了只能传入Polygon及其子类。
还有一只是改变参数数量的重载,同样是因为PHP也不支持方法的重载,所以也需要些变通的方法实现,如下:
<?php
// 通过可变参数来达到改变参数数量重载的目的
// 不是必须传入的参数,必须在函数定义时赋初始值
function open_database($DB, $cache_size_or_values=null, $cache_size=null)
{
switch (function_num_args()) // 通过function_num_args()函数计算传入参数的个数,根据个数来判断接下来的操作
{
case 1:
$r = select_db($DB);
break;
case 2:
$r = select_db($DB, $cache_size_or_values);
break;
case 3:
$r = select_db($DB, $cache_size_or_values, $cache_size);
break;
}
return is_resource($r);
}
?>
三、克隆
PHP5中的对象模型是通过引用来调用对象的,但有时需要建立一个对象的副本,改变原来的对象时不希望影响到副本。如果使用“new”关键字重新创建对象,再为属性赋上相同的值,这样做会比较繁琐而且也容易出错。在PHP中可以根据现有的对象克隆出一个完全一样的对象,克隆以后,原本和副本两个对象完全独立,互不干扰。在PHP5中使用“clone”关键字克隆对象,示例如下:
<?php
class Person
{
public $name;
function __construct($name="" )
{ $this->name =$name;
}
function say()
{ echo "我叫:". $this->name ."<br>" ;
}
}
$Person=new Person( "张三");
$Person1=clone $Person; //使用clone关键字克隆(复制)对象,创建一个对象的副本
// $Person1=$Person //这不是复制对象,而是为对象多复制出一个访问该对象的引用
$Person->say();
$Person1->say();
?>
上面程序运行结果为:
我叫:张三
我叫:张三
克隆的副本和原本拥有相同的类和属性
if($Person == $Person1)
{ echo "Person和Person1具有相同的类和属性" ; }
else
{ return false; }
程序输出:Person和Person1具有相同的类和属性
克隆的副本和原本存储在不相同的位置
if ($Person === $Person1)
{
echo "Person和Person1具有相同的类和属性且存储在相同的位置" ;
}
else
{
return false ;
}
程序结果为false。
克隆的副本和原本独立而互不干扰
我们来改变一下原本的属性值,看一下有什么影响
$Person=new Person( "张三"); $Person1=clone $Person; $Person1-> name='李四' ; $Person->say(); $Person1->say();
程序运行结果为:
我叫:张三
我叫:李四
由此可知,克隆出来的副本和原本两个对象完全独立而互不干扰。
__clone()方法
如果需要为克隆后的副本对象克隆时重新为成员属性赋值,可以在类中声明一个魔术方法"__clone"
<?php class Person { public $name; function __construct($name="" ) { $this->name =$name; } function __clone(){//在对象克隆时自动调用,用来为新对象重新赋值 $this->name ='李四' ; } function say() { echo "我叫:". $this->name ."<br>" ; } } $Person=new Person( "张三"); $Person1=clone $Person; $Person->say(); $Person1->say(); ?>
程序运行结果为:
我叫:张三
我叫:李四