Menu
CoddyTech

__get、__set、__isset、__unset

本课属于 Coddy PHP 学习旅程的“面向对象编程”单元。第 46 课,共 91 课。

PHP 提供了 4 个拦截属性访问的魔术方法:__get()、__set()、__isset() 和 __unset()。当你尝试访问不存在或无法访问的属性时,就会触发这些方法。

读取不可访问的属性时会调用 __get() 方法,而 __set() 用于处理对这类属性的写入。这样你就可以创建动态属性,或在访问属性时添加逻辑:

<?php
class DynamicObject {
    private array $data = [];
    
    public function __get(string $name): mixed {
        return $this->data[$name] ?? null;
    }
    
    public function __set(string $name, mixed $value): void {
        $this->data[$name] = $value;
    }
}

$obj = new DynamicObject();
$obj->title = "Hello";
$obj->count = 42;
echo $obj->title . " - " . $obj->count;

输出:

Hello - 42

__isset() 方法会由 isset() 或 empty() 触发,而 __unset() 会响应 unset() 函数:

<?php
class DynamicObject {
    private array $data = [];
    
    public function __set(string $name, mixed $value): void {
        $this->data[$name] = $value;
    }
    
    public function __isset(string $name): bool {
        return isset($this->data[$name]);
    }
    
    public function __unset(string $name): void {
        unset($this->data[$name]);
    }
}

$obj = new DynamicObject();
$obj->name = "Test";
echo isset($obj->name) ? "exists" : "missing";

输出:

exists

这些方法常用于创建灵活的数据容器、实现懒加载,或构建行为类似数组的对象,同时保持面向对象的结构。

challenge icon

挑战

简单

让我们构建一个灵活的配置管理器,使用魔术方法动态存储设置。你的类会拦截属性访问,以管理配置值、检查设置是否存在,并在需要时删除设置:整个过程无需显式定义每个属性。

你将把代码分成两个文件:

  • Config.php:创建一个 Config 类,使用私有数组在内部存储配置值。实现全部四个属性魔术方法:
    • __get($name):返回给定键对应的值;如果键不存在,则返回 "undefined"
    • __set($name, $value):将值存储在给定键下
    • __isset($name):返回配置中是否存在该键
    • __unset($name):从配置中删除该键
    此外,还要添加一个 count() 方法,返回已存储设置的数量。
  • main.php:引入 Config 文件。你会收到 3 个输入:一个设置名称、一个设置值,以及第二个设置名称。创建一个 Config 实例,并执行以下操作:
    • 将第一个设置设为给定值
    • 使用 isset() 输出第一个设置是否存在:输出 "exists" 或 "missing"
    • 输出第一个设置的值
    • 输出当前设置数量
    • 使用 unset() 删除第一个设置
    • 输出第一个设置现在是否存在:输出 "exists" 或 "missing"
    • 输出第二个设置的值(该设置从未被设置)

每项输出都应单独占一行。借助魔术方法,你可以使用自然的属性语法与 Config 对象交互,例如 $config->theme = "dark" 和 isset($config->theme),即使没有定义任何实际属性也可以。

亲手试试

<?php

require_once 'Config.php';

// 读取输入
$settingName1 = trim(fgets(STDIN));
$settingValue = trim(fgets(STDIN));
$settingName2 = trim(fgets(STDIN));

// TODO:创建一个 Config 实例

// TODO:将第一个设置设为给定值

// TODO:输出第一个设置是否存在("exists" 或 "missing")

// TODO:输出第一个设置的值

// TODO:输出当前设置的数量

// TODO:使用 unset() 移除第一个设置

// TODO:输出第一个设置现在是否存在("exists" 或 "missing")

// TODO:输出第二个设置的值(该设置从未被设置过)

?>
quiz icon自我测试

这节课包含一个小测验。开始学习即可作答,并记录你的进度。

面向对象编程中的所有课

自己练习: PHP 在线编译器