当前位置: 首页 > news >正文

PHP魔术方法深入理解与实战

PHP魔术方法深入理解与实战

魔术方法是PHP中特殊的方法,以两个下划线开头,在特定情况下自动调用。理解魔术方法可以写出更灵活的代码。今天详细说说各种魔术方法的使用场景。

__construct和__destruct是最常用的魔术方法。对象创建时自动调用__construct,销毁时调用__destruct。

```php
class Connection
{
private ?PDO $pdo = null;

public function __construct(
private string $dsn,
private string $user,
private string $pass
) {
echo "连接对象创建\n";
}

public function connect(): PDO
{
if ($this->pdo === null) {
$this->pdo = new PDO($this->dsn, $this->user, $this->pass);
}
return $this->pdo;
}

public function __destruct()
{
$this->pdo = null;
echo "连接对象销毁\n";
}
}
?>
```

属性重载的魔术方法。__get、__set、__isset、__unset用于拦截属性访问。

```php
class DynamicProperties
{
private array $data = [];
private array $readonly = ['id', 'created_at'];

public function __get(string $name): mixed
{
echo "读取属性: $name\n";
return $this->data[$name] ?? null;
}

public function __set(string $name, mixed $value): void
{
if (in_array($name, $this->readonly)) {
throw new RuntimeException("只读属性: $name");
}
echo "设置属性: $name = " . json_encode($value) . "\n";
$this->data[$name] = $value;
}

public function __isset(string $name): bool
{
echo "检查属性是否存在: $name\n";
return isset($this->data[$name]);
}

public function __unset(string $name): void
{
echo "删除属性: $name\n";
unset($this->data[$name]);
}
}

$obj = new DynamicProperties();
$obj->name = "张三";
echo $obj->name . "\n";
echo isset($obj->name) ? "存在" : "不存在" . "\n";
unset($obj->name);
?>
```

方法重载的__call和__callStatic。当调用不存在的方法时触发。

```php
class QueryBuilder
{
private array $conditions = [];
private array $orders = [];
private ?int $limit = null;

public function __call(string $name, array $arguments): self
{
if (str_starts_with($name, 'where')) {
$field = lcfirst(substr($name, 5));
$this->conditions[] = [$field, $arguments[0]];
return $this;
}

if (str_starts_with($name, 'orderBy')) {
$field = lcfirst(substr($name, 7));
$this->orders[] = [$field, $arguments[0] ?? 'asc'];
return $this;
}

throw new BadMethodCallException("方法不存在: $name");
}

public function limit(int $limit): self
{
$this->limit = $limit;
return $this;
}

public function getQuery(): string
{
$sql = "SELECT * FROM table";
if (!empty($this->conditions)) {
$parts = array_map(fn($c) => "{$c[0]} = :{$c[0]}", $this->conditions);
$sql .= " WHERE " . implode(' AND ', $parts);
}
if (!empty($this->orders)) {
$parts = array_map(fn($o) => "{$o[0]} {$o[1]}", $this->orders);
$sql .= " ORDER BY " . implode(', ', $parts);
}
if ($this->limit !== null) {
$sql .= " LIMIT {$this->limit}";
}
return $sql;
}
}

$query = (new QueryBuilder())
->whereName('张三')
->whereAge(28)
->orderById('desc')
->orderByName()
->limit(10);

echo $query->getQuery() . "\n";
?>
```

__toString方法在对象被当作字符串使用时调用。

```php
class Money
{
public function __construct(
private float $amount,
private string $currency = 'CNY'
) {}

public function __toString(): string
{
$symbols = ['CNY' => '¥', 'USD' => '$', 'EUR' => '€'];
$symbol = $symbols[$this->currency] ?? $this->currency;
return $symbol . number_format($this->amount, 2);
}

public function add(Money $other): Money
{
if ($this->currency !== $other->currency) {
throw new InvalidArgumentException("货币不匹配");
}
return new Money($this->amount + $other->amount, $this->currency);
}
}

$price = new Money(99.99);
$tax = new Money(13.00);
$total = $price->add($tax);
echo "价格: $price\n";
echo "税费: $tax\n";
echo "总计: $total\n";
?>
```

__invoke让对象可以作为函数调用。

```php
class Logger
{
private string $logFile;

public function __construct(string $logFile = '/tmp/app.log')
{
$this->logFile = $logFile;
}

public function __invoke(string $message, string $level = 'INFO'): void
{
$line = sprintf("[%s] %s: %s\n", date('Y-m-d H:i:s'), $level, $message);
file_put_contents($this->logFile, $line, FILE_APPEND | LOCK_EX);
}
}

$log = new Logger();
$log("用户登录成功"); // 对象作为函数调用
$log("数据库连接失败", "ERROR");

echo "日志已写入\n";
?>
```

__clone魔术方法在clone对象时调用,控制深拷贝行为。

```php
class Order
{
public function __construct(
public string $id,
public array $items,
public \DateTime $createdAt
) {}

public function __clone(): void
{
// 深拷贝对象属性
$this->createdAt = clone $this->createdAt;

// 深拷贝数组中的对象
foreach ($this->items as &$item) {
if (is_object($item)) {
$item = clone $item;
}
}
unset($item);
}
}

$order1 = new Order('ORD-001', ['商品A', '商品B'], new \DateTime());
$order2 = clone $order1;
$order2->id = 'ORD-002';

echo "原始: {$order1->id}\n";
echo "克隆: {$order2->id}\n";
echo "时间不同: " . ($order1->createdAt !== $order2->createdAt ? '是' : '否') . "\n";
?>
```

__serialize和__unserialize(PHP7.4+)控制序列化行为。

```php
class SecureUser
{
public function __construct(
public string $name,
private string $password,
private string $token
) {}

public function __serialize(): array
{
return [
'name' => $this->name,
// 不序列化敏感信息
];
}

public function __unserialize(array $data): void
{
$this->name = $data['name'];
$this->password = '';
$this->token = '';
}
}
?>
```

魔术方法让PHP的对象系统更加灵活。属性重载可以实现动态属性,方法重载可以实现DSL风格的接口,序列化控制可以保护敏感数据。但魔术方法也有一些缺点,比如IDE自动补全可能不准确,增加理解难度。使用时要权衡灵活性和可维护性。

http://www.jsqmd.com/news/947361/

相关文章:

  • 郑州市 家电维修清洗上门|维小达空调、冰箱、洗衣机、热水器、电视、油烟机灶具、消毒柜、小家电一站式维保清洗服务 - 维小达科技
  • 魔兽争霸III终极性能优化:三大核心功能免费解决宽屏适配、地图加载与帧率限制
  • Arxiv上传前必读:关于撤稿、专利与源码政策的那些‘坑’,科研新人如何提前规避?
  • Qwen3.6-Plus工程落地指南:Agent底座的可交付实践
  • 基于深度学习+AI的电梯内电动车目标检测与预警系统(Python源码+数据集+UI可视化界面+YOLOv11训练结果)
  • 用Multisim 14.2从零搭建一个三路抢答器:我的课程设计实战与避坑全记录
  • 工地PPE实时检测工具:PyQt5界面+YOLOv8模型,支持安全帽/马甲/面具三类识别
  • 从啤酒瓶到二维码:手把手教你复用Gazebo官方模型,打造自定义贴图仿真资产
  • AI生成可玩游戏:单文件HTML卡丁车实战指南
  • SQL 无关联条件拼接
  • PHP国际化与多语言支持实现
  • SAIL系统架构:SRAM与查找表优化LLM推理性能
  • 开源报表工具JimuReport实战:手把手教你配置SQL数据源并生成动态销售报表
  • AI工具如何重塑法律服务效率?揭秘2024智能法务整合的7个关键决策点
  • 如何在5分钟内快速上手B站视频下载神器downkyi:完整使用指南
  • PHP图像处理与GD库实战
  • 道路积水数据集 路面积水识别数据集 图片数量4524,xml和txt标签都有;公路积水数据集 ✓类别:puddle;
  • CAPL数据处理避坑指南:当byte数组遇上Hex字符串,这些细节你注意了吗?
  • Spartan-6 FPGA上跑通AD9238双路12位25MHz实时采集的完整ISE工程包
  • C#抽象类 接口(简答 + 答题话术)
  • 性价比最高的仓储软件(WMS)怎么选 - 品牌排行榜
  • 第九章:Token 优化与高效省钱配置(重点)
  • 3分钟快速部署智慧树自动刷课插件:彻底解放双手的终极学习助手
  • 2026年|迎战5月查重死线!10款全网最火降AI工具亲测,零成本高效降AI率指南 - 降AI实验室
  • 气缸驱动并联机器人位姿控制策略【附仿真】
  • Vue版Cesium卫星轨道+雷达扫描三维可视化组件(含CZML数据与小程序适配)
  • 2026年6月可靠的工业皮带生产厂家推荐,输送带/工业皮带/pvc输送带/食品输送带,工业皮带源头厂家有哪些 - 品牌推荐师
  • 联想AI主机Mini: 优质AI订阅替代方案实测
  • PHP图像识别与QR码生成技术
  • 语义内核形式化模型:AI内容生成的统一数学原理与工程实践