面向对象编程(Object Oriented Programming),简称OOP。
它将真实世界各种复杂的关系,抽象为一个个对象,然后由对象之间的分工与合作,完成对真实世界的模拟。
面向对象的特性:
在声明一个类时,使用class
关键字,声明这个类的与这个类所在的文件最好同名。
Student
类:
class Student {
// 在这里面声明成员属性和方法
}
类的属性和方法有三种:
以下是声明了一个Student
类,以及类中的属性和方法的案例。
class Student
{
// 属性:变量
// 公有属性,外部、本类和子类可以访问
public $name;
// 受保护成员,仅限本类以及子类访问
protected $gender;
// private: 私有成员,仅限本类中的使用
private $age;
private static $score;
// 构造函数
// __construct()属于魔术方法,由系统自动调用
// 在类的实例化过程中会调用它
public function __construct($name, $gender, $age)
{
$this->name = $name;
$this->gender = $gender;
$this->age = $age;
}
// 方法
public function getStuInfo() {
return "姓名:{$this->name},性别:{$this->gender},年龄:{$this->age}岁。";
}
}
实例化Student
类:
$stu = new Student('张三', '男', 16);
echo $stu->getStuInfo();
以上结果将输出:姓名:张三,性别:男,年龄:16岁。
访问类中的公有属性:
echo $stu->name; // 张三
当一个类的成员或方法被声明成了静态(static),那么,就无法通过类实例去访问了,必须使用类直接调用。
class Staff {
public $name;
// 静态成员
public static $salary;
// 构造函数
public function __construct(string $name, int $salary)
{
$this->name = $name;
// 静态成员与类实例无关,因此不能用$this访问,直接使用类去调用
self::$salary = $salary;
}
public static function staffSalary() {
return '员工的工资:'.self::$salary;
}
}
实例化Staff
类:
$staff = new Staff('张三', 8899);
// 使用类名访问静态属性
echo Staff::$salary; // 8899
// 使用类名访问静态方法
echo Staff::staffSalary(); // 员工的工资:8899
类的继承使用extends
关键字,也就是对类的功能进行扩展。
require 'Student.php';
class Sub extends Student {
// 类的继承一般有两个用处:
// 1. 对父类方法进行重写;
// 2. 对父类功能进行扩展。
// 扩展一个属性,score:分数
private $score;
// 子类构造器,重写了父类的方法
public function __construct($name, $gender, $age, $score)
{
// 调用父类成员
parent::__construct($name, $gender, $age);
$this->score = $score;
}
// 重写父类的getStuInfo()方法
public function getStuInfo()
{
return parent::getStuInfo()."分数:{$this->score}";
}
// 增加一个新方法,判断学生成绩是否及格。
public function isPass()
{
if ($this->score > 60) {
return "该学生成绩已及格,分数为:{$this->score}";
}
}
}
$sub = new Sub('张三', '男', 16, 90);
echo $sub->getStuInfo(); // 姓名:张三,性别:男,年龄:16岁。分数:90
echo "<br>";
echo $sub->isPass(); // 该学生成绩已及格,分数为:90
以上案例分别输出结果:
姓名:张三,性别:男,年龄:16岁。分数:90
该学生成绩已及格,分数为:90
Trait 是为类似 PHP 的单继承语言而准备的一种代码复用机制。Trait 为了减少单继承语言的限制,为了使开发者能复用某些方法。
可以把trait理解为一个公共方法集,它借用了class语法实现了一个轻量级的“类”,但它不是类,所以不能实例化。
trait userInfo {
public function getUserInfo () {
return "This is userInfo " . $this->name;
}
}
class User
{
// 使用关键字use引入需要使用的trait
use userInfo;
}
trait userInfo {
public function getUserInfo () {
return "This is userInfo " . $this->name;
}
}
class UserBase
{
public $username;
// 引用trait
use userInfo;
public function __construct($username)
{
$this->username = $username;
}
public function getUserInfo () {
return "This is UserBase " . $this->name;
}
public function getUserName() {
return "UserBase:".$this->username;
}
}
以上代码在trait
中和UserBase
类中都声明了一个getUserInfo()
方法,当在getUserInfo()
类中引入trait里面的方法之后我们创建类实例,然后调用getUserInfo()
方法,发现调用的是UserBase
类里面的getUserInfo()
方法。
trait冲突解决办法
当我同时声明了两个trait中有两个相同的方法getUserInfo()
,那么在类中访问的时候回报错,具体案例如下:
trait user1 {
public function getUserInfo () {
return "This is user1 ";
}
}
trait user2 {
public function getUserInfo () {
return "This is user2 ";
}
}
class User {
use user1;
use user2;
}
以上代码会报错:Trait method getUserInfo has not been applied,because there are collisions with other trait methods on User in
E:\phpstudy_pro\WWW\phpcn\PHP\20210202\demo5.php on line 59
。
解决办法是:优先级与别名:
trait user1 {
public function getUserInfo () {
return "This is user1 ";
}
}
trait user2 {
public function getUserInfo () {
return "This is user2 ";
}
}
class User {
use user1, user2 {
// 1.优先级
user1::getUserInfo insteadof user2;
// 2.别名
user2::getUserInfo as user2GetUserInfo;
}
}
echo (new User('张三'))->getUserInfo(); // This is user1
echo (new User('张三'))->user2GetUserInfo(); // This is user2
当父类trait与当前子类中存在同名成员时,如何解决?
class SubUser extends User
{
use user3;
public function fun () {
return __METHOD__;
}
}
此时的结果是:SubUser::fun
,说明子类的优先级高于父类的。
如果在父类与子类之间加了一个trait里面的一个同名函数,此时的优先级是什么样呢?
trait user3{
public function fun () {
return __METHOD__;
}
}
class SubUser extends User
{
use user3;
public function fun () {
return __METHOD__;
}
}
echo (new SubUser())->fun(); // SubUser::fun
如果此时子类SubUser
中没有fun
方法呢?
trait user3{
public function fun () {
return __METHOD__;
}
}
class SubUser extends User
{
use user3;
}
echo (new SubUser())->fun(); // user3::fun
此时的结果是:user3::fun
。
这时,我们可以得出这个优先级的结果:自己拥有的 > trait > 父类的。