从0开始学PHP面向对象内容之(常用魔术方法续一)

常用魔术方法(续)

上期我们讲到几个常用的魔术方法,但是由于篇幅过程且全是文字性质地东西,就没写完,篇幅太长也会丧失阅读兴趣,我尽量控制一篇文章在5000字左右

一、__isset()&&__unset()

1、在开发中,类通常有一些不想暴露或让外部检查的私有或受保护的属性,比如密码、敏感配置等。通过 __isset(),可以控制这些属性是否能够被 isset() 或 empty() 检查到。
2、__isset() 的主要用途 :是控制对象中是否可以检测到某个属性,通常用于保护敏感数据和实现延迟加载。
__unset() 的主要用途:是定义对象在使用 unset() 时的行为,通常用于控制哪些属性可以被删除或在删除时执行附加逻辑。

1、数据隐藏与控制访问

1、__isset() 和 __unset() 常用于对象中属性的访问控制,尤其是当类有一些私有属性时,这些方法可以决定哪些属性可以被检查或销毁。
2、__isset() 可以用 :来控制 isset() 和 empty() 是否能正确判断属性的存在性。
__unset() 可以用:来决定是否允许 unset() 删除某个属性。

示例
php 复制代码
class User {
    private $data = [
        'username' => 'john_doe',
        'email' => 'john.doe@example.com',
        'password' => 'hashed_password' // 敏感信息
    ];

    public function __isset($name) {
        // 阻止 `password` 属性被 `isset()` 检查
        if ($name === 'password') {
            return false;
        }
        return isset($this->data[$name]);
    }
}

$user = new User();
var_dump(isset($user->username)); // 输出 true
var_dump(isset($user->password)); // 输出 false,即使 `password` 实际上存在
应用场景

1、保护敏感数据,防止它们在调试或其他场景中暴露。

2、控制哪些属性能够被检查是否存在,提升代码安全性。

2、动态属性管理

在很多应用程序中,类的属性是动态存储的,例如配置类、缓存类、或从数据库获取的数据对象。使用 __isset() 和 __unset(),可以灵活地管理这些动态属性。

示例
php 复制代码
class Config {
    private $settings = [];

    public function __set($name, $value) {
        $this->settings[$name] = $value;
    }

    public function __get($name) {
        return $this->settings[$name] ?? null;
    }

    public function __isset($name) {
        // 检查动态属性是否已设置
        return array_key_exists($name, $this->settings);
    }

    public function __unset($name) {
        // 删除动态属性
        unset($this->settings[$name]);
    }
}

$config = new Config();
$config->app_name = 'MyApp';

// 检查属性是否存在
var_dump(isset($config->app_name)); // 输出 true

// 删除属性
unset($config->app_name);
var_dump(isset($config->app_name)); // 输出 false
应用场景

1、用于配置类或设置类,动态管理属性,确保灵活性和可扩展性。

2、控制对象中存储的临时或动态数据的访问和修改。

3、延迟加载与内存优化

在大型系统中,延迟加载(Lazy Loading)是一种重要的设计模式,它允许在需要时才加载对象的某些部分。通过 __isset() 可以实现对属性是否存在的延迟检测,这样只有在实际访问时才执行昂贵的计算或数据加载。

示例
php 复制代码
class DataLoader {
    private $data;

    public function __get($name) {
        // 延迟加载数据
        if ($name === 'largeData' && $this->data === null) {
            $this->data = $this->loadData();
        }
        return $this->data;
    }

    public function __isset($name) {
        // 检查是否需要加载数据
        if ($name === 'largeData') {
            return $this->data !== null;
        }
        return false;
    }

    private function loadData() {
        // 模拟数据加载
        return "Loaded Data";
    }
}

$loader = new DataLoader();

// 检查属性,延迟加载还未触发
var_dump(isset($loader->largeData)); // 输出 false

// 访问属性,触发延迟加载
echo $loader->largeData; // 输出 "Loaded Data"

// 再次检查属性
var_dump(isset($loader->largeData)); // 输出 true
应用场景

1、在访问大数据对象时确保仅在必要时加载,避免不必要的内存占用。

2、结合 __get(),实现对象中某些复杂数据的惰性初始化。

4、复杂对象结构的可控销毁

通过 __unset(),可以确保某些重要数据不会被外部轻易删除,或在删除时执行一些清理操作。

示例
php 复制代码
class Cache {
    private $cache = [
        'item1' => 'data1',
        'item2' => 'data2',
    ];

    public function __unset($name) {
        // 防止 `item1` 被删除
        if ($name === 'item1') {
            echo "item1 不允许被删除。\n";
            return;
        }
        unset($this->cache[$name]);
    }
}

$cache = new Cache();
unset($cache->item2); // 正常删除
unset($cache->item1); // 输出 "item1 不允许被删除。"
应用场景

1、防止关键属性被无意中删除。

2、在删除对象属性时需要执行额外的清理或日志记录操作

二、__clone()

1、__clone() 是 PHP 中的一个魔术方法,用于控制对象被克隆时的行为。

2、__clone() 方法允许你自定义克隆对象的行为,以实现更复杂的对象复制逻辑。

3、__clone() 方法在使用 clone 关键字克隆对象时自动调用。它可以用于调整新克隆对象的状态,比如复制引用类型的属性、重置一些属性值、或处理特定逻辑。

1、实现深拷贝

当一个对象的属性中包含其他对象时,PHP 默认的 clone 关键字会创建一个浅拷贝,这意味着属性中引用的对象不会被克隆,仍会指向原对象。通过 __clone() 方法,可以确保深拷贝,从而避免原始对象和克隆对象共享引用。

示例
php 复制代码
class Node {
    public $data;
    public $child;

    public function __clone() {
        if ($this->child !== null) {
            $this->child = clone $this->child; // 确保子对象也被克隆
        }
    }
}

$node1 = new Node();
$node1->data = "Parent";
$node1->child = new Node();
$node1->child->data = "Child";

$node2 = clone $node1; // 深拷贝,`child` 属性被单独克隆
$node2->child->data = "Modified Child";

echo $node1->child->data; // 输出 "Child"
echo $node2->child->data; // 输出 "Modified Child"
应用场景

1、处理复杂数据结构,如树形结构或图结构。

2、需要在克隆后修改子对象,以避免意外共享引用。

2、防止共享状态

当一个对象的某些属性指向外部资源或缓存时,克隆时共享这些引用可能导致冲突或意外行为。通过 __clone(),可以确保克隆对象有独立的副本。

示例:
php 复制代码
class Cache {
    public $data;

    public function __construct($data) {
        $this->data = $data;
    }

    public function __clone() {
        $this->data = clone $this->data; // 确保 `data` 独立拷贝
    }
}
应用场景:

在克隆时创建独立的数据缓存副本。

避免克隆对象与原对象共享同一连接、文件句柄或其他资源。

3、对象重置和初始化

在一些情况下,克隆后的对象需要进行特定的重置或重新初始化。通过 >__clone(),可以修改属性、生成新的唯一 ID 或重置状态。

示例:
php 复制代码
class Session {
    public $id;
    public $createdAt;

    public function __construct() {
        $this->id = uniqid();
        $this->createdAt = time();
    }

    public function __clone() {
        // 在克隆时重新生成唯一 ID 和时间戳
        $this->id = uniqid();
        $this->createdAt = time();
    }
}

$session1 = new Session();
$session2 = clone $session1; // 克隆并生成新的 ID 和时间戳

echo "Original Session ID: " . $session1->id . "\n";
echo "Cloned Session ID: " . $session2->id . "\n";
应用场景

克隆对象时生成新 ID,确保唯一性。

在克隆后重置时间戳、状态标志等。

4、预防克隆操作

在某些情况下,你可能希望防止对象被克隆。通过在 __clone() 中抛出异常,可以实现这一点。

示例
php 复制代码
class Singleton {
    private static $instance;

    private function __construct() {
        // 私有构造函数,防止外部实例化
    }

    public static function getInstance() {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    public function __clone() {
        throw new \Exception("Cloning of this object is not allowed.");
    }
}

$instance = Singleton::getInstance();

try {
    $clone = clone $instance;
} catch (\Exception $e) {
    echo $e->getMessage(); // 输出 "Cloning of this object is not allowed."
}
应用场景:

单例模式,确保对象实例是唯一的。

防止意外克隆,保护对象状态。

5、复制复杂对象中的引用属性

在包含其他对象的复杂对象中,使用 __clone() 可以确保这些引用类型的属性被正确地复制,以防止在修改克隆对象时影响原始对象。

示例:
php 复制代码
class Car {
    public $engine;

    public function __construct($engine) {
        $this->engine = $engine;
    }

    public function __clone() {
        $this->engine = clone $this->engine; // 确保引擎属性被克隆
    }
}

class Engine {
    public $type;

    public function __construct($type) {
        $this->type = $type;
    }
}

$engine1 = new Engine("V8");
$car1 = new Car($engine1);

$car2 = clone $car1;
$car2->engine->type = "V6";

echo $car1->engine->type; // 输出 "V8"
echo $car2->engine->type; // 输出 "V6"
应用场景:

克隆包含依赖关系的对象。

在克隆时将部分属性复制为新的实例。

相关推荐
开心工作室_kaic17 分钟前
ssm161基于web的资源共享平台的共享与开发+jsp(论文+源码)_kaic
java·开发语言·前端
向宇it19 分钟前
【unity小技巧】unity 什么是反射?反射的作用?反射的使用场景?反射的缺点?常用的反射操作?反射常见示例
开发语言·游戏·unity·c#·游戏引擎
武子康24 分钟前
Java-06 深入浅出 MyBatis - 一对一模型 SqlMapConfig 与 Mapper 详细讲解测试
java·开发语言·数据仓库·sql·mybatis·springboot·springcloud
转世成为计算机大神1 小时前
易考八股文之Java中的设计模式?
java·开发语言·设计模式
黑客Ash1 小时前
【D01】网络安全概论
网络·安全·web安全·php
->yjy1 小时前
计算机网络(第一章)
网络·计算机网络·php
宅小海1 小时前
scala String
大数据·开发语言·scala
qq_327342731 小时前
Java实现离线身份证号码OCR识别
java·开发语言
锅包肉的九珍1 小时前
Scala的Array数组
开发语言·后端·scala
心仪悦悦1 小时前
Scala的Array(2)
开发语言·后端·scala