《PHP类的基础概念:从零开始学面向对象》

《PHP类的基础概念:从零开始学面向对象》

什么是"类"?------ 你的设计图纸

想象你要开一家机器人制造工厂。你需要一张"设计图纸",上面画着机器人该有什么"部件"(比如名字、型号)和"功能"(比如行走、说话)。在 PHP 里, "类"(Class)就是这张设计图纸

kotlin 复制代码
// Robot 类:机器人设计图纸
class Robot {
    // ... 在这里定义部件和功能
}

类本身不是机器人,它是制造机器人的模板

类里有什么?------ 你的三大法宝

一张完整的图纸包含三样东西:

  1. 常量 (Constants)固定不变的设定。

    • const MAX_SPEED = 100; // 所有机器人的最高速度上限
    • 一旦定义,永远不能改变。
  2. 属性 (Properties) :机器人的"部件 "或"特征"。

    • public $name; // 机器人的名字
    • public $color; // 机器人的颜色
    • 属性是机器人的"身份证信息"。
  3. 方法 (Methods) :机器人的"功能 "或"动作"。

    • public function walk() { ... } // 机器人走路的功能
    • public function speak($words) { ... } // 机器人说话的功能
    • 方法是机器人的"技能包"。

📌 重要提示 :在方法内部定义的变量(如 function walk() { $step = 1; } 中的 $step)是局部变量 ,只在该方法执行时存在,用完就消失,它不是类结构的一部分。

创建机器人(实例化)------ 用图纸造机器

有了图纸,就可以造机器人了!这叫"实例化 "。使用 new 关键字。

ini 复制代码
$myRobot = new Robot(); // 造一个机器人

$myRobot 就是根据 Robot 类创造出来的具体机器人 ,我们称之为"对象 "或"实例"。

new 操作符的进化:PHP 8.0+ 的任意表达式支持

在 PHP 8.0 之前,new 后面只能跟固定的类名

ini 复制代码
// PHP 8.0 之前
$className = 'Robot';
$instance = new $className(); // 需要变量,写法稍显别扭

从 PHP 8.0.0 起,new 可以用在任意表达式中,这带来了巨大的灵活性和简洁性!

php 复制代码
// ✅ PHP 8.0+ 新写法:直接在表达式中使用 new

// 1. 从函数返回类名
function getRobotClass(): string {
    return 'Robot';
}
$robot1 = new (getRobotClass());

// 2. 字符串拼接
$robot2 = new ('Rob' . 'ot');

// 3. 使用 ::class 常量
class AdvancedRobot {}
$robot3 = new (AdvancedRobot::class);

// 4. 创建后立即调用方法
echo (new DateTime())->format('Y-m-d'); // 创建 DateTime 对象并调用 format
// 注意:从 PHP 8.4 起,括号 ( ) 可以省略:echo new DateTime()->format('Y-m-d');

💡 关键点

  • new ($className) 这种写法在 PHP 8.1+ 被标记为"软弃用",强烈推荐使用 new ($expression) 的新语法
  • 给构造函数传参 :如果类有构造函数需要参数,直接在表达式后的括号里传入即可:new (<expression>)(<arg1>, <arg2>)
php 复制代码
// 假设 Robot 构造函数需要 name 和 age
class Robot {
    public function __construct(string $name, int $age) { ... }
}
// 正确传参方式
$robot = new ('Rob' . 'ot')('小助手', 5);

对象的"引用"特性 ------ 一个机器人,多个遥控器

记住核心规则:对象变量默认是"引用" ,而不是"值"。

ini 复制代码
$robot1 = new Robot();
$robot2 = $robot1; // $robot2 不是新机器人,而是指向 $robot1 的"遥控器"

$robot2->name = "小助手"; // 通过 $robot2 的遥控器改名字

echo $robot1->name; // 输出:小助手 ❗

为什么? 因为 $robot1$robot2 指向的是同一个机器人实体。改一个,另一个也跟着变。

继承:机器人升级 ------ extends

PHP 支持"机器人升级"。新机器人可以继承旧机器人的所有部件和功能,然后添加自己的新东西。

scala 复制代码
class SuperRobot extends Robot { // SuperRobot 继承 Robot
    public $laser; // 新增激光武器

    public function fly() { // 新增飞行功能
        echo "起飞!";
    }
}
  • extends 表示继承。
  • 重要限制 :PHP 不支持多重继承,一个机器人只能有一个"爸爸"(基类)。
覆盖 (Override) 与 Final

新机器人可以改进旧功能。

scala 复制代码
class SuperRobot extends Robot {
    // 覆盖父类的 speak 方法
    public function speak($words) {
        echo "超级机器人说:" . $words;
    }
}
  • 覆盖规则 (LSP - 里氏替换原则)

    • 方法签名(参数)必须兼容。不能删除父类方法的必需参数。
    • 可以增加可选参数。
    • 不能收紧访问权限(比如父类 public,子类不能改成 private)。
  • 覆盖的例外

    • 构造函数 (__construct) :子类构造函数的签名不需要 与父类兼容。子类可以有自己独立的参数列表(但仍需通过 parent::__construct() 调用父类构造函数来初始化父类部分)。
    • private 方法 :子类可以定义一个与父类 private 方法同名的方法,但这不是覆盖 ,而是完全独立的方法 ,因为 private 方法在子类中不可见。
  • Final 关键字 :如果父类方法或常量被标记为 final,子类绝对不能覆盖它,这是"最终设定"。

::class ------ 获取类的全名

需要知道一个类的完整名称(尤其带命名空间时)?用 ::class

php 复制代码
namespace Factory\Robots;

class WorkerRobot {}

echo WorkerRobot::class; // 输出: Factory\Robots\WorkerRobot

// 对象也可以用 (PHP 8.0+)
$robot = new WorkerRobot();
echo $robot::class; // 输出: Factory\Robots\WorkerRobot

Nullsafe 操作符 ?-> ------ 安全调用

不确定机器人是否存在或有某个功能?用 ?-> 安全调用。

ini 复制代码
// 自 PHP 8.0.0 起可用  
$result = $repository?->getUser(5)?->name;  
  
// 上边那行代码等价于以下代码  
if (is_null($repository)) {  
$result = null;  
} else {  
$user = $repository->getUser(5);  
if (is_null($user)) {  
$result = null;  
} else {  
$result = $user->name;  
}  
}
相关推荐
RainCity14 分钟前
Java Swing 自定义组件库分享(六)
java·笔记·后端
techdashen18 分钟前
深入 Rust enum 的内存世界
开发语言·后端·rust
龙码精神36 分钟前
TimescaleDB 物联网设备属性历史数据表设计及常用SQL文档
后端
小小小小宇1 小时前
Go 后端锁机制详解
后端
挖坑的张师傅1 小时前
你的仓库 Agent Ready 了吗?
后端
客场消音器1 小时前
如何使用codex进行UI重构,让AI开发的前端页面不再千篇一律
前端·后端·微信小程序
Full Stack Developme2 小时前
spring-beans 解析
java·后端·spring
苏三说技术2 小时前
为什么大厂都不推荐在MySQL中使用NULL值?
后端
techdashen2 小时前
Rust 模块和文件不是一回事:一次讲清 `mod`、`use`、`pub use`
开发语言·后端·rust
爱勇宝2 小时前
别焦虑,也别躺平:给年轻程序员的一封信
前端·后端·架构