后端基础【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
| <?php
class cat { public $name; public $age; public $color; } $cat1= new cat; $cat1->name="mingming"; $cat1->age=18; $cat1->color="yellow";
$cat2= new cat; $cat2->name="honghong"; $cat2->age=16; $cat2->color="pink"; if ($cat1->name="mingming"){ echo $cat1->name."|".$cat1->age."|".$cat1->color.'<br/>'; }if ($cat2->name="honghong"){ echo $cat2->name."|".$cat2->age."|".$cat2->color; }
?>
|

根据案例发现,类是抽象的,表示一类事物,对象是具体的,表示类的一个具体实例。类是对象的模板,对象是类的一个个具体实例。
类的创建格式:
成员属性可以是基本数据类型也可以是复合数据类型(数组、对象)。
对象的创建格式:
1 2 3 4 5 6
| $对象名 = new 类名(); 或者 $对象名 = new 类名;
访问对象的属性 $对象名 -> 属性名;
|
构造函数
构造函数:在创建对象时直接给属性赋值。
构造函数是类的一种特殊函数,主要作用是完成对新对象的初始化。
两个特点:1.没有返回值;2.在创建一个类的对象时,系统会自动调用该类的构造函数完成对新对象的初始化。
案例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| <?php
class Person { public $name; public $age;
public function __construct($name, $age) { $this->name = $name; $this->age = $age; } } $cat1 = new Person("xiaohong",5); echo $cat1->name; echo '<hr />'; echo $cat1->age;
?>
|

注意:构造函数在类中只能有一个,并且不能手动调用。它只能在创建新对象时自动调用。
代码中所使用的$this,它会指向当前对象,更深一步,就是这个对象的地址。哪个对象使用$this,就指向哪个对象的地址,$this不能再类外部使用。
析构函数
析构函数是另一种特殊的函数,用于在对象销毁时执行清理操作。
当对象不再被使用时,PHP会自动调用析构函数。与构造函数一样,析构函数的名称必须与类名相同,并且不带参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <?php
class MyClass { public function __construct() { echo 'Object created.'; }
public function __destruct() { echo 'Object destroyed.'; } } $test = new MyClass;
?>
|

在创建新的对象时,并输出一条消息“Object created.”。当脚本结束或对象不再被使用时,PHP将自动销毁该对象,并输出一条消息“Object destroyed.”。
需要注意的是,析构函数的执行时机不受程序员的控制。当对象不再被使用时,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
| <?php class Child{ public $name; public static $sums=0; function __construct($name) { $this-> name = $name; }
function JChild(){ self::$sums += 1; echo $this-> name.'加入游戏'; echo "<hr />"; } } $child1=new Child("Ming"); $child1->JChild(); $child2=new Child("Zhang"); $child2->JChild(); $child3=new Child("Lin"); $child3->JChild(); echo '<br/>'."一共".Child::$sums."个小孩"; ?>
|

1、静态变量的修饰符为static;
2、静态变量的访问方式:
如果是在类的外部访问:类名::$类变量名
如果是在类的内部访问:类名::$类变量名 或者 self::$类变量名
注意:访问静态变量和是否创建对象无关,你不创建对象,也可以访问。访问静态变量,禁止使用$this,否则程序会报错。
静态方法
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 Child{ public $name; public static $sums=0; function __construct($name) { $this-> name = $name; }
static function JChild(){ Child::$sums += 1; }
function Join(){ echo $this-> name.'加入游戏'; echo "<hr />"; } } $child1 = new Child("Ming"); $child1->Join(); $child1->JChild(); $child2=new Child("Zhang"); $child2->JChild(); $child2->join(); $child3=new Child("Lin"); $child3->JChild(); $child3->join(); echo '<br/>'."一共".Child::$sums."个小孩"; ?>
|

静态方法和静态变量是对应的,只能调用静态变量,如果调用非静态变量它是会报错的。不过,反过来可以,即普通成员函数是可以调用静态变量的。原因是静态变量和静态方法都属于这个类,并且都是公开的。
封装
封装主要介绍三个修饰符,分别是public(公开的)、protected(受保护的)、private(私有的)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <?php class Person{ public $name; protected $age; private $wage; public function __construct($name,$age,$wage){ $this-> name = $name; $this-> age = $age; $this-> wage = $wage; } } $p1=new Person("Ming",18,1000); echo $p1->name; echo $p1->age; echo $p1->wage; ?>
|

protected(受保护的)与 private(私有的)这两个修饰符修饰的变量不能直接调用。要想调用,就需要写一个公开的方法,再直接调用方法就可以。
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
| <?php class Person{ public $name; protected $age; private $wage; public function __construct($name,$age,$wage){ $this-> name = $name; $this-> age = $age; $this-> wage = $wage; } public function PersonAge(){ echo $this->age; echo "<hr />"; } public function PersonWage(){ echo $this->wage; echo "<hr />"; }
} $p1=new Person("Ming",18,1000); echo $p1->name; echo "<hr />"; echo $p1->PersonAge(); echo $p1->PersonWage(); ?>
|

你可能会有疑问,我们直接调就可以了,为什么要多走这一步?这是因为在方法里我们可以对变量进一步控制,比如加个范围,权限再控制得细一些等。也可以用另外一种方法,即PHP为我们提供的魔术方法:
1 2
| __set()对protected或是private属性,进行赋值操作 __get()获取protected或是private属性的值
|
继承
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| <?php
class Student{ public $name; public $age; public $studentID;
public function ShowInfo($name,$age){ echo $this-> name = $name." | ".$this-> age = $age; } }
class universityStudent extends Student{ public function study(){ echo " 正在学习 "; } }
$u1 = new universityStudent(); $u1-> ShowInfo("Ming",22); $u1-> study(); ?>
|

子类可以使用父类的方法,这就解决了代码重复的问题。如果想要使用继承,关键字“extends”。所谓继承就是子类通过“extends”关键字,把父类的(public、protected)属性和(public、protected)方法继承下来。
还需注意,只能继承public、protected属性和public、protected方法,private的属性和方法只能在本类中使用。
在PHP中子类最多只能继承一个父类(指直接继承),在创建某个子类对象时,默认情况不会自动调用其父类的构造函数。
如果想调用父类的构造函数,可以通过在子类的代码中加入:“父类名::构造函数名”或者“parent::构造函数名”两种方法实现
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 Student{ public $name; public $age; public $studentID;
public function __construct(){ echo "我是父类的构造函数"; }
public function ShowInfo($name,$age){ echo $this-> name = $name." | ".$this-> age = $age; } }
class universityStudent extends Student{ public function study(){ echo " 正在学习 "; }
public function __construct(){ Student::__construct(); echo " 我是子类的构造函数 "." <br/>"; } }
$u1 = new universityStudent(); $u1-> ShowInfo("Ming",22); $u1-> study(); ?>
|

多态
函数重载
重载是类的多态的一种实现,是指一个标识符被用作多个函数名,并且能够通过参数个数或参数类型将这些同名的函数区分开,调用不发生混淆。
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
| <?php class A{ public $name; public $age; public function test1($a){ echo "hello,123"; } public function test2($a){ echo "hello,456"; } public function __call($name, $arguments) //定义call方法,会自动调用这个方法 // __call为PHP的魔术方法
//$name:被调用的方法的名称 //$arguments:一个包含传递给方法参数的数组
{ var_dump($arguments);
if($name=="test"){ if(count($arguments)==1){ $this->test1($arguments); }elseif (count($arguments)==2){ $this->test2($arguments); } } } } $a = new A();
$a-> test(1); $a-> test(2,6); ?>
|

注意:
1 2 3 4 5 6 7 8 9
| public function test(){ echo "hello,123"; } public function test($a){ echo "hello,456"; }
如果我们这么写,PHP会报错,其他的语言可以。
|
方法重写(覆盖)
假设我们设计一个类,提取一些相同的特征,设计成父类,并有一些函数,而子类想要完善父类的方法,只需要在子类中将方法的命名设为和父类相同,参数也完全相同就可以了。我们把它叫作方法重写(覆盖)。如果子类想要调用父类的方法,可以使用parent::方法名()。
子类方法不能缩小父类方法的访问权限,但可以扩大。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <?php
class A{ public function Reset(){ echo "父类的reset方法"; } }
class B extends A{ public function Reset(){ parent::Reset(); echo '<hr />'; echo "子类的reset方法"; } }
$obj = new B; $obj-> reset();
?>
|

抽象类
之所以设计抽象类,是为了快速开发,我们可能遇到这样的类,它是其他类的父类,但它本身并不需要实例化,主要是用于子类去继承。这样可以达到代码复用的目的,并且有利于项目设计者设计类。
抽象类格式:
1 2 3
| abstract class 类名{ abstract 修饰符 function 函数名(参数列表);//这里要注意,没有方法体。 }
|
抽象类不能被实例化。抽象类不一定要包含abstract方法。也就是说,抽象类可以没有abstract方法。一旦类包含了abstract方法,则这个类必须声明为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
| <?php interface iTest{ public function start(); public function stop(); } class camera implements iTest{ public function start(){ echo "计算机开始工作"; } public function stop(){ echo "计算机停止工作"; } } class phone implements iTest{ public function start(){ echo "手机开始工作"; } public function stop(){ echo "手机停止工作"; } } $c1=new camera(); $c1->start(); $c1->stop(); echo "<br/>"; $p1=new phone(); $p1->start(); $p1->stop(); ?>
|

接口比抽象类更抽象,所以,接口更不能被实例化了。接口中所有的方法都不能有主体。
一个类可以实现多个接口,用逗号隔开。
1 2
| public class A implements 接口1,接口2{ }
|
接口中可以有属性,但必须是常量,默认是public。接口中的方法必须是public,默认也是public。一个接口不能继承其他的类,但是可以继承别的接口。
1 2
| interface 接口名 extends 接口1,接口2{ }
|
如果我们希望某个类不被其他类继承,我们可以使用final关键字来修饰这个类。
final关键字通过在定义方法和常量之前加上 final 来防止被子类覆盖。 如果一个类被声明为 final,则不能被继承。
注意,如果我们用final来修饰某个类中的方法,则这个方法无法被重写。final也不能用来修饰成员属性。