PHP基础知识(三、多态)

多态

多态的概念:只抽象的声明父类,具体的工作由子类对象来完成,这样,不同的子类对象完成,有不同的特点

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
class Light{
public function turn_on($arg){
$arg -> show();
}
}

class RedGlass{
public function show(){
echo "我是红灯","<br />";
}
}

class YellowGlass{
public function show(){
echo "我是黄灯","<br />";
}
}

class GreenGlass{
public function show(){
echo "我是绿灯","<br />";
}
}


$light = new Light();
$red = new RedGlass();
$yellow = new YellowGlass();
$green = new GreenGlass();
$light -> turn_on($red);
$light -> turn_on($yellow);
$light -> turn_on($green);

如果按PHP本身的特点,不检测类型,本身就可以说是多态的,甚至是变态的额,但是PHP5.3以后,引入了对于对象类型的参数检测,注意,只能检测对象所属的类,其实对于PHP来说,限制了其灵活性,达到Java中多态的效果。

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
35
36
37
//类Java多态
class Light{
public function turn_on(Glass $arg){
$arg -> show();
}
}

class Glass{

}

class RedGlass extends Glass{
public function show(){
echo "我是红灯","<br />";
}
}

class YellowGlass extends Glass{
public function show(){
echo "我是黄灯","<br />";
}
}

class GreenGlass extends Glass{
public function show(){
echo "我是绿灯","<br />";
}
}


$light = new Light();
$red = new RedGlass();
$yellow = new YellowGlass();
$green = new GreenGlass();
$light -> turn_on($red);
$light -> turn_on($yellow);
$light -> turn_on($green);

静态属性与静态方法

在属性和方法前加static修饰,这种称为静态属性或方法

  • 从内存角度看,statics属性,存放在类的区域中,普通属性存放在对象中
  • 类声明完毕,静态属性就存在,不需要依赖于对象来访问
  • 因为类在内存中只有一个,因此静态属性也只有一个,被所有对象共享(一个类中可有多个静态属性或方法)
1
2
3
4
class Human{
static public $head = 1;
}
echo Human::$head;
  • 非静态方法,是不能由类名静态调用的,但是,PHP中的面向对象检测并不严格,只要该方法中没有$this,就会转化为静态方法来调用
  • self与parent详解

  • self:调用自身类中的属性或方法
  • parent:调用父类中的属性或方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class A{
public function a1(){
echo "this is function a1()";
}
}

class B extends A{
public function b1(){
$this -> a1();
}

public function b2(){
parent::a1();
}
}

$b = new B();
$b -> b1();
$b -> b2();
  • 从速度角度看,parent速度稍快一点点,因为子类再找a1()方法时,寻找不到,再找父类
  • 但是从面向对象的角度看,继承过来的就是自己的,$this更符合面向对象的思想,因为当继承的层次很深时,用parent::parent::parent::parent这样的方式明显不是很合理
  • 但是当想访问父类的私有属性时,可以通过parent::parent::parent::parent这种方式实现

单例模式

在PHP程序开发过程中,为了规范程序设计,使用单例模式对创建对象进行技术规范,避免重复,随意创建对象
final在PHP中可以修饰类和方法,不能修饰属性

  • 修饰类时,被修饰的类不能被继承(其不能有子类)
  • 修饰方法时,该方法可以被继承,但是不能被重写
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Single{
public $random = null;
static protected $ins = null;
final protected function __construct(){
$this -> random = mt_rand(1,10);
}
static public function getInstance(){
if(self::$ins instanceof self){ //判断一个对象是不是属于该类
return self::$ins;
}else{
self::$ins = new self();
return self::$ins;
}
}
}

class son extends Single{

}
$t1 = son::getInstance();
$t2 = son::getInstance();
print_r($t1);
print_r($t2);

单例模式主要思路

1.类有一个静态属性存放对象

2.保护或私有构造函数,防止外部实例化

3.内部开放一个公共的静态方法,负责实例化

4.当静态属性已经存放该对象,直接return该对象,否则,先实例化在return

魔术方法

  • __get():如果访问的属性没有权限或者不存在,则会自动调用这个魔术方法,并自动把不能访问或者不存在的属性名作为参数,传入方法。
  • __set():当为无权操作或者不存在的属性赋值时,方法会被自动调用,且自动传入两个参数,分别是属性和属性值。
  • __isset():判断对象不可见属性时(private/protected/不存在),会引发方法执行
  • __unset():销毁对象不可见属性时(private/protected/不存在),会引发方法执行,并自动把想销毁的属性名作为参数,传入方法。
  • __call():调用一个不能访问或不存在的方法时,会被自动调用,且自动传入两个参数,分别是不能被调用的方法名和以数组形式返回的不能调用的方法的参数
  • __callstatic():调用一个不能访问或不存在的静态方法时,会被自动调用,且自动传入两个参数,分别是不能被调用的方法名和以数组形式返回的不能调用的方法的参数

重写与重载

  • 重写/覆盖:子类重写了父类的同名方法
  • 重载:存在多个同名方法,但参数类型或个数不同,传入的参数不同,调用的方法不同,但PHP中不行,因为PHP一个类中不允许有多个同名方法

类常量与魔术常量

  • 普通常量:define(‘name’,’value’);无论是页面内,类内还是函数类都可以访问
  • 类内常量:cons name = ‘lihua’;只能在类内访问

延迟绑定(运行期绑定)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Human{
public static function who(){
echo "在父类执行";
}
public static function say(){ //子类没有say方法,找到父类,这里的self指父类
self::who();
}
public static function say1(){
//子类没有say1方法,找到父类,但是父类调用的是静态方法,调用子类自己的who方法
static::who();
}
}

class Stu extends Human{
public static function who(){
echo "在子类执行";
}
}

$t = new Stu();
$t::say();
$t::say1();

抽象类

  • 抽象类:用abstract修饰,不能被实例化,继承抽象类的子类要实现抽象类中的所有抽象方法
  • 抽象方法:用abstract修饰,不能包含方法体(大括号内的内容)
  • 有抽象方法,此类必是抽象类,但在抽象类中,不一定有抽象方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
abstract class Rocket{
public abstract function engine();

public abstract function balance();
}

class Plane extends Rocket{
public function engine(){
echo "涡扇发动机";
}

public function balance(){
echo "平衡舵";
}
}

$plane = new Plane();
$plane -> engine();

接口的概念

因为接口的方法本身就是抽象的,;不要有方法体,也不要有abstract

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
35
36
37
38
interface animal{
public function eat();
}

interface monkey{
public function run();
public function cry();
}

interface wisdom{
public function think();
}

interface bird{
public function fly();
}

class Human implements animal,monkey,wisdom{
public function eat(){
echo "吃";
}

public function run(){
echo "跑";
}

public function cry(){
echo "哭";
}

public function think(){
echo "思考";
}

}

$lisi = new Human();
$lisi -> think();

接口语言与应用场景

  • 接口本身即是抽象的,内部声明的方法默认也是抽象的,不用加abstract
  • 一个类可以一次性实现多个接口,语法用implements实现,然后再把接口的功能给实现
  • 接口也可以继承,用extends
  • 接口是一堆方法的说明,不能加属性
  • 接口的方法必须是公共的

自动加载

如果调用某个不存在的类,在报错之前,我们还有一次介入机会,系统会自动调用autoload()函数,并把类名自动传给autoload()函数

1
2
3
4
5
6
7
function __autoload($c){
require('./'.$c.'.php')

}

$lisi = new Human();
$t -> run();