面向对象之继承
面向对象之继承
一、什么是继承
对象的继承是指从一个类派生出另外的一个类的过程,就像孩子是从父母那里继承品性一样。
- 关键字 extends
- PHP只能有一个父类
- 关键词 instanceof 可以用来查看一个特别的对象是不是属于一种特定的类的类型
require 'demo.class.php';
$obj = new ChildClass();
if( $obj instanceof Demo ){
$obj->test();
}
1、全部继承
子类继承(也就是具有)父类的全部属性和方法
class Person
{
public $name;
public $age;
public $info;
public function __construct($name,$age,$info)
{
$this->name = $name;
$this->age = $age;
$this->info = $info;
}
public function talk(){
return '你好面试官,我叫' . $this->name . ',今年'.$this->age . ',特长:'. $this->info;
}
}
class Man extends Person
{
}
$jack = new Man('jack',18,'帅的令人发指');
echo $jack->talk();
2、部分继承
子类还可以添加自己的成员,从而可以保持和父类有所区别
class Man extends Person
{
public function checkAge(){
return $this->age>=18 ? '拉出去当壮丁' : '还是小鲜肉';
}
}
$jack = new Man('jack',18,'帅的令人发指');
echo $jack->talk();
echo $jack->checkAge();
3、无限多子继承
class Man extends Person
{
public function checkAge(){
return $this->age>=18 ? '拉出去当壮丁' : '还是小鲜肉';
}
}
class Women extends Person {
}
二、访问控制
封装 我们为什么要使用面向对象编程呢?既然只需要使用方法就可以写出复杂且实用的网站? OOP的真正价值在于封装,它的意义在于将相互关联的一组值和函数封装在一起,组成一个编程单元
封装的概念 : 通过修饰符 改变成员属性或者成员方法的访问权限,达到保护的作用。
修饰符 | public | protected | private |
---|---|---|---|
本类内 | Y | Y | Y |
子类内 | Y | Y | N |
外部 | Y | N | N |
类的属性和成员方法在哪里可以用、可以被访问
class User extends Demo
{
public $username = 'jack';
protected $truename = '老聂';
private $age = '18';
public function printInfo(){
echo $this->username;
echo $this->truename;
echo $this->age;
}
private function secret(){
echo "这是个秘密!";
}
}
- 一个公共的(Public)成员可以从任何一个地方访问:类本身内部,派生的子类和其他类。
- 类的受保护的(protected)成员只能在类本身以及子类中访问。
- 私有(private)的限制是最严格的,这些成员只能在声明它们的类中进行访问。私有的类成员不能被子类或者这些类的一个对象实例访问到。
聂哥友情备注:作为一个惯例,私有变量名通常以一个下划线开始。这在很多面向对象编程语言中都是这样做的,即便它并不是必须这样做
访问修饰符的范围
子类复写父类中的方法时,子类中的 访问修饰符的范围要大于等于 父类的【 继承只能发扬光大,至少保持不变。不可以丢失东西。
在UML中的体现
+
公共的-
私有的#
受保护的
三、继承中的构造方法和析构方法
在子类里父类的构造函数会不会执行,分两种情况:
- 如子类不定义构造函数
__construct()
,则父类的构造函数默认会被继承下来,且会自动执行。 - 如子类定义了构造函数
__construct()
,因为构造函数名也是__construct()
,所以子类的构造函数实际上是覆盖(override)了父类的构造函数。这时执行的是该子类的构造函数
class Demo
{
function __construct()
{
echo '正在进行构造...<br/>';
}
function test(){
echo '这是什么地方<br/>';
}
function __destruct()
{
echo '正在进行析构...<br/>';
}
}
class ChildClass extends Demo
{
function __construct()
{
//如果要在子类里执行父类的构造函数
//parent::__construct();
echo '我是后代构造函数-正在进行构造...<br/>';
}
}
注意
parent::__construct()
; 语句不一定必须放在子类的构造函数中。放在子类的构造函数中仅仅保证了其在子类被实例化时自动执行。
四、重写
重载就是函数或者方法有相同的名称,但是参数列表不相同的情形,这样的同名不同参数的函数或者方法之间,互相称之为重载函数或者方法。PHP不支持,但可用构造方法实现。
重写又叫覆盖,就是将父类继承下来的属性或方法重新定义,只有保护的或公共的属性或方法能够被重写。
1、重写一个方法,子类定义的方法必须和父类的方法具有完全相同的名称和参数数量。
class Person
{
public $name;
public $age;
public $info;
public function __construct($name,$age,$info)
{
$this->name = $name;
$this->age = $age;
$this->info = $info;
}
public function talk($fuhao){
return '你好面试官,我叫' . $this->name . ',今年'.$this->age . ',特长:'. $this->info;
}
}
class Man extends Person
{
public function checkAge(){
return $this->age>=18 ? '拉出去当壮丁' : '还是小鲜肉';
}
public function talk(){
}
}
2、PHP5.3+
方法重写必须要相同个数的参数,如果非多个参数,这时要给其他参数设置默认值
class Person
{
public $name;
public $age;
public $info;
public function __construct($name,$age,$info)
{
$this->name = $name;
$this->age = $age;
$this->info = $info;
}
private function talk($fuhao){
return '你好面试官,我叫' . $this->name . ',今年'.$this->age . ',特长:'. $this->info;
}
}
class Man extends Person
{
public function checkAge(){
return $this->age>=18 ? '拉出去当壮丁' : '还是小鲜肉';
}
public function talk($fuhao='没办法,我是来充数的'){
}
}
3、私有属性或私有方法的重写问题
- 私有属性和方法不能覆盖,但其实子类可以定义跟父类私有的同名属性或方法,只是当做一个自身的新属性或方法来看待而已。
参数必须保持一致(PHP5.4前)
class A
{
private $name = '山炮';
public function getName()
{
return $this->name;
}
}
class B extends A
{
private $name = '二货';
public function getTest()
{
return $this->getName().$this->name;
}
}
$b = new B;
echo $b->getTest();//山炮二货
3.2 访问私有属性 类中的私有属性或者方法是不能被继承的,但是当一个父类A中的方法FunA,调用了父类A中的Private私有属性或着方法的时,这个FunA在被继承以后,将能继续通过$this
访问父类A中的Private私有属性或者方法,无论继承子类中对父类A中的私有属性或方法如何重新实现,直到FunA在继承子类中被重写
class A
{
private $name = '山炮';
public function getName()
{
return $this->name;
}
}
class B extends A
{
public $name = '二货';
}
$b = new B;
echo $b->name; //二货
echo $b->getName(); //山炮
4、构造方法重写问题,比较宽松,重写的时候参数可以不一致。
class Person
{
public $name;
public $age;
public $info;
public function __construct($name,$age,$info)
{
$this->name = $name;
$this->age = $age;
$this->info = $info;
}
private function talk($fuhao,$cans=''){
return '你好面试官,我叫' . $this->name . ',今年'.$this->age . ',特长:'. $this->info;
}
}
class Man extends Person
{
public function __construct()
{
echo '我的方法没有参数';
}
}
$jack = new Man();
5、非完全重写
class Person
{
public $name;
public $age;
public function __construct($name,$age)
{
$this->name = $name;
$this->age = $age;
}
public function talk(){
return '你好面试官,我叫' . $this->name . ',今年'.$this->age;
}
}
class Man extends Person
{
public $info;
public function __construct($name,$age,$info)
{
parent::__construct($name,$age);
$this->info = $info;
}
public function talk(){
return '我先敲门!'.parent::talk().',特长:'.$this->info;
}
}
$jack = new Man('jack',18,"帅的令人发指");
echo $jack->talk();
五、不允许继承或重写 final
1.类里绝大部分方法,都是可以重写的。唯一的例外就是被定义了FINAL的方法:
final function myFunc(){
}
- 属性不能被定义为 final,只有类和方法才能被定义为 final。
- final关键字应该放在其他修饰符protect/public/private/static之前。
- 定义为final的方法不能被任何子类所重写。
- 类也可以声明为final,这意味着它不能被扩展。
2. 不能继承的类
final A{
}