面象对向的三大特点:封装性、继承性、多态性 首先简单理解一下抽象:
我们在前面定义一个类的时候,实际上就是把一类事物共有的属性和行为提取出来,形成一个物理模型(模版),这种研究问题的方法称为抽象
封装性 封装就是把抽取出来的数据和对数据的操作封装在一起,数据被保护在内部,程序的其他部分只有被授权的操作(方法)才能对数据进行操作。
php提供了三种访问控制修饰符
public 表示全局,本类内部,类外部,子类都可以访问
protected 表示受保护的,只有本类或子类可以访问
private 表示私有的,只有本类内部可以访问
以上三种修饰符既可以修饰方法也可以修饰属性(变量),方法如果没有访问修饰符则默认是public,成员属性必须指定访问修饰符,在PHP4中也有这种写法 var $name,表示公开属性,不推荐这种写法
例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 <?php class Person { public $name ; protected $age ; private $salary ; function __construct ($name , $age , $salary ) { $this ->name = $name ; $this ->age = $age ; $this ->salary = $salary ; } public function showinfo ( ) { echo $this ->name."||" .$this ->age."||" .$this ->salary; } } $p1 = new Person ('张三' , 20 , 3000 );echo $p1 ->salary;?>
那么现在就想在外部访问protected和private的元素和方法该怎么办? 通常做法是通过public函数去访问这些变量 格式:
1 2 3 4 5 6 7 8 public function setxxxx ($val ) { $this ->xxxx = $val ; } public function getxxxx ( ) { return $this ->xxxx; }
这里带set和get只是为了识别方便,并非必要
如:
1 2 3 4 5 public function getsalary ( ) { return $this ->salary; }
在外部就可以通过 echo $p1->getsalary();
如果要访问 protected和private也可以使用以下方法,但不推荐使用,只要了解即可
__set() 和 __get()
__set()对protected或private属性进行赋值操作
__set($pro_name, $pro_val);
__get()获取 protected 或 private的值
__get($pro_name);
如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 <?php class testa { protected $name ; public function __set ($pro_name , $pro_val ) { $this ->pro_name = $pro_val ; } public function __get ($pro_name ) { if (isset ($pro_name )) { return $this ->pro_name; } else { return null ; } } } $n1 = new testa ();$n1 ->name = '小三' ;echo $n1 ->name;?>
继承性 先看一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <?php class Pupil { public $name ; protected $age ; public function getinfo ( ) { echo $this ->name.'||' .$this ->age; } public function testing ( ) { echo 'this is pupil' ; } } class Graduate { public $name ; protected $age ; public function getinfo ( ) { echo $this ->name.'||' .$this ->age; } public function testing ( ) { echo 'this is Graduate' ; } } ?>
从上面的例子可以看出,当多个类有很多共同属性和方法时,代码的复用性不高,代码冗余,思考css中的处理方法
解决方法:继承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 <?php class Students { public $name ; public $age ; public function __construct ($name , $age ) { $this ->name = $name ; $this ->age = $age ; } public function showinfo ( ) { echo $this ->name.'||' .$this ->age; } } class Pupil extends Students { function testing ( ) { echo 'Pupil ' .$this ->name.' is testing' ; } } class Graduate extends Students { function testing ( ) { echo 'Graduate ' .$this ->name.' is testing' ; } } $stu1 = new Pupil ('张三' , 20 );$stu1 ->showinfo ();echo '<br/>' ;$stu1 ->testing ();?>
从上面可以看出,继承就是一个子类(Subclass)通过 extends 父类 把父类(BaseClass)中的public 和 protected 的属性和方法继续下来,不能继承private属性和方法
语法结构:
1 2 3 4 5 6 class 父类名 {} class 子类名 extends 父类名 {}
细节:
1、一个子类只能继承一个父类(这里指直接继承);如果希望继承多个类的属性和方法,可以使用多层继承
例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 <?php class A { public $name = 'AAA' ; } class B extends A { public $age = 30 ; } class C extends B {} $p = new C ();echo $p ->name;?>
2、在创建某个子类对象时,默认情况下不会自动调用其父类的构造函数
例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class A { public function __construct ( ) { echo 'A' ; } } class B extends A { public function __construct ( ) { echo 'B' ; } } $b = new B ();
3、在子类中如果需要访问父类的方法(构造方法、成员方法 方法的修饰符为protected或private),那么可以使用 父类::方法名 或者 parent::方法名 来完成【这里parent和以前提到的self都均为小写,大写报错】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class A { public function test ( ) { echo 'a_test' ; } } class B extends A { public function __construct ( ) { A::test (); parent ::test (); } } $b = new B ();
5. 如果一个子类(派生类)的方法与父类的方法完全一样时(public,protected),我们称为方法覆盖或方法重写(override),看下面的多态性 多态性 例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 <?php class Animal { public $name ; public $price ; function cry ( ) { echo 'i don\'t know' ; } } class Dog extends Animal { function cry ( ) { echo 'Wang Wang!' ; Animal ::cry (); } } $dog1 = new Dog ();$dog1 ->cry ();?>
小结:
当一个父类知道所有的子类都有一个方法,但是父类不能确定该方法如何写,可以让子类去覆盖它的方法,方法覆盖(重写),必须要求子类的方法名和参数个数完全一致
如果子类要去调用父类的某个方法(protected/public),可以使用 父类名::方法名 或者 parent::方法名
在实现方法重写的时候,访问修饰符可以不一样,但是子类方法的访问权限必须大于等于父类方法的访问权限(即不能缩小父类方法的访问权限)
如 父类public function cry(){} 子类 protected function cry(){} 则会报错
但是子类的访问权限可以放大,如:
父类private function cry(){} 子类 protected function cry(){} 可以正确执行
扩展:
方法重载(overload)
基本概念:函数名相同,但参数的个数或参数的类型不同,达到调用同一个函数,可以区分不同的函数
在PHP5中虽然也支持重载,但是和其它语言还是有很大区别的,php中不能定义多个同名函数
PHP5中提供了强大的“魔术”函数,使用这些魔术函数,我们可以做到函数重载,
这里我们要到到 __call,当一个对象调一个方法时,而该方法不存在,则程序会自动调用__call
【官方不推荐使用】
PHP中有以下几个魔术常量:__LINE__ __FILE__ __DIR__ __FUNCTION__ __CLASS__ 等
例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <?php class A { function test1 ($p ) { echo 'test1<br/>' ; } function test2 ($p ) { echo 'test2<br/>' ; } function __call ($method , $p ) { if ($method == 'test' ) { if (count ($p )==1 ) { $this ->test1 ($p ); } else if (count ($p )==2 ) { $this ->test2 ($p ); } } } } $a = new A ();$a ->test (5 );$a ->test (3 , 5 );?>
本文早期发布于个人 CSDN 博客:查看原文