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

在这里插入图片描述

一、什么是魔术方法

PHP中的魔术方法是以__两个下划线开头的方法,这些方法提供了一种机制,可以在类的生命周期中拦截某些事件或者进行一些操作

二、魔术方法有哪些

一、__construct()&&__destruct()

  1. __construct()构造函数,__destruct()析构函数,这两个上期文章中讲到过在这就不再赘述了

二、__call()&&__callStatic()

用于处理未定义的方法调用,尝试调用不存在的方法或静态方法时PHP解释器会自动调用__call()方法
参数:将原本要调用的方法名和参数列表作为参数传递给该方法。这样可以在运行时动态处理方法调用,从而实现更灵活的对象行为

  1. __call():当调用一个对象中不存在或不可访问的方法时触发

  2. __callStatic():当调用一个类中不存在或不可访问的静态方法时触发。

示例:

class MagicMethods {public function __call($name, $arguments) {echo "尝试调用方法 '$name',参数为:" . implode(', ', $arguments) . "\n";}public static function __callStatic($name, $arguments) {echo "尝试调用静态方法 '$name',参数为:" . implode(', ', $arguments) . "\n";}
}$obj = new MagicMethods();
$obj->nonExistentMethod('param1', 'param2');  // 输出 "尝试调用方法 'nonExistentMethod',参数为:param1, param2"
MagicMethods::nonExistentStaticMethod('staticParam1');  // 输出 "尝试调用静态方法 'nonExistentStaticMethod',参数为:staticParam1"

应用场景:

在这里就不做具体介绍了,因为我没咋用过,等我研究研究在再进行详细介绍,用到最多的功能就是他的拦截日志方法的调用,记录那些方法被调用,以便进行调试或监控。

  1. 实现动态代理

在面向对象编程中,__call() 和 __callStatic() 可以用于实现方法调用的动态代理,将方法请求委托给另一个对象。这在构建装饰器或代理模式时非常有用。

class Proxy {private $realObject;public function __construct($realObject) {$this->realObject = $realObject;}public function __call($name, $arguments) {echo "代理对象调用方法 '$name',参数:" . implode(', ', $arguments) . "\n";return call_user_func_array([$this->realObject, $name], $arguments);}public static function __callStatic($name, $arguments) {echo "代理对象调用静态方法 '$name',参数:" . implode(', ', $arguments) . "\n";// 在静态代理中处理逻辑}
}class RealObject {public function doSomething($param) {return "真实对象处理了:$param";}
}$realObj = new RealObject();
$proxy = new Proxy($realObj);echo $proxy->doSomething('Task');  // 输出 "代理对象调用方法 'doSomething',参数:Task" 和 "真实对象处理了:Task"

在大型应用程序中使用代理模式,为对象的调用添加日志、缓存或权限验证逻辑。
为第三方 API 客户端提供动态代理以封装请求。

  1. 实现多态行为

在需要通过不同的方法名称来触发类似操作的场景中,__call() 和 __callStatic() 可以简化代码,比如创建动态的 getter 和 setter 方法。

class DynamicMethods {private $data = [];public function __call($name, $arguments) {if (preg_match('/^get(.+)$/', $name, $matches)) {$property = strtolower($matches[1]);return $this->data[$property] ?? null;}if (preg_match('/^set(.+)$/', $name, $matches)) {$property = strtolower($matches[1]);$this->data[$property] = $arguments[0];return $this;}throw new BadMethodCallException("方法 '$name' 不存在");}public static function __callStatic($name, $arguments) {echo "静态方法 '$name' 被调用,参数:" . implode(', ', $arguments) . "\n";// 静态方法处理逻辑}
}$obj = new DynamicMethods();
$obj->setName('John')->setAge(30);
echo $obj->getName();  // 输出 "John"
echo $obj->getAge();   // 输出 "30"

快速实现对象属性的动态 getter 和 setter 方法,减少重复代码。
创建灵活的工厂方法,动态生成实例。

  1. 日志记录与监控

使用 __call() 和 __callStatic() 实现方法调用的监控和日志记录,以便调试或审计。

class Logger {public function __call($name, $arguments) {echo "调用了实例方法 '$name',参数:" . json_encode($arguments) . "\n";// 在此处添加日志写入逻辑}public static function __callStatic($name, $arguments) {echo "调用了静态方法 '$name',参数:" . json_encode($arguments) . "\n";// 在此处添加静态日志写入逻辑}
}$logger = new Logger();
$logger->trackEvent('userLogin', ['userId' => 123]);  // 输出 "调用了实例方法 'trackEvent',参数:[\"userLogin\",{\"userId\":123}]"Logger::logEvent('systemStart');  // 输出 "调用了静态方法 'logEvent',参数:[\"systemStart\"]"

在开发调试过程中捕获未定义的方法调用并记录日志。
为应用程序添加额外的审计和监控功能,而无需显式定义每个方法。

  1. 简化 API 客户端设计

在构建访问外部服务的 API 客户端时,__call() 可以用于动态构建方法以适应 API 的多样性。

class APIClient {public function __call($name, $arguments) {$endpoint = strtolower($name);$params = !empty($arguments) ? json_encode($arguments[0]) : '{}';echo "调用 API 端点 '$endpoint',参数:$params\n";// 在此处进行实际的 API 请求return "返回的 API 响应";}
}$client = new APIClient();
$response = $client->getUser(['id' => 1]);  // 输出 "调用 API 端点 'getuser',参数:{\"id\":1}"
echo $response;  // 输出 "返回的 API 响应"
  1. 实现通用调用处理

在构建框架或工具库时,__call() 和 __callStatic() 可以作为通用入口,处理对未知或动态行为的请求。

class FrameworkHandler {public function __call($name, $arguments) {echo "处理实例方法调用 '$name',执行通用逻辑\n";// 根据 $name 和 $arguments 进行处理}public static function __callStatic($name, $arguments) {echo "处理静态方法调用 '$name',执行通用逻辑\n";// 根据 $name 和 $arguments 进行静态处理}
}$handler = new FrameworkHandler();
$handler->runTask();  // 输出 "处理实例方法调用 'runTask',执行通用逻辑"FrameworkHandler::startProcess();  // 输出 "处理静态方法调用 'startProcess',执行通用逻辑"

在框架中提供灵活的调用接口,通过名称匹配处理不同的任务。
在工具库中动态响应未知或变化的需求。

三、__get()&&__set()

一般来说,总是把类的属性定义为private,这更符合现实的逻辑。但是,对属性的读取和赋值操作是非常频繁的,因此在中,预定义了两个函数“__get()”和“__set()”来获取和赋值其属性

  1. __get(): 试图读取不可访问或不存在的属性时调用
  2. __set():试图给不可访问或不存在的属性赋值时调用。

示例:

class PropertyTest {private $data = [];public function __get($name) {echo "获取属性 '$name'\n";return isset($this->data[$name]) ? $this->data[$name] : null;}public function __set($name, $value) {echo "设置属性 '$name' 为 '$value'\n";$this->data[$name] = $value;}
}$obj = new PropertyTest();
$obj->name = 'ChatGPT';  // 输出 "设置属性 'name' 为 'ChatGPT'"
echo $obj->name;         // 输出 "获取属性 'name'" 并显示 "ChatGPT"

应用场景:

__get() 和 __set() 是 PHP 中的魔术方法,允许开发者在对象访问或设置未定义或私有属性时,自定义其行为。这在增强对象的灵活性和保护属性访问方面非常有用:

  1. 实现动态属性访问

使用 __get() 和 __set() 可以实现对未定义或私有属性的访问和设置,从而避免显式定义大量的 getter 和 setter 方法。

class DynamicProperties {private $data = [];public function __get($name) {echo "访问属性 '$name'\n";return $this->data[$name] ?? null;}public function __set($name, $value) {echo "设置属性 '$name' 为 '$value'\n";$this->data[$name] = $value;}
}$obj = new DynamicProperties();
$obj->title = 'Hello World';  // 输出 "设置属性 'title' 为 'Hello World'"
echo $obj->title;             // 输出 "访问属性 'title'" 并显示 "Hello World"

在动态处理类属性时,减少显式声明的代码量。
访问未定义的属性时提供默认行为,避免未定义属性引起的错误。

  1. 数据封装和保护

__get() 和 __set() 可以用来实现对私有属性的访问控制,确保数据在访问或修改时进行验证和安全检查。

class User {private $attributes = [];public function __get($name) {if (!array_key_exists($name, $this->attributes)) {throw new Exception("属性 '$name' 不存在");}return $this->attributes[$name];}public function __set($name, $value) {if ($name === 'password') {// 对密码进行加密处理$value = password_hash($value, PASSWORD_DEFAULT);}$this->attributes[$name] = $value;}
}$user = new User();
$user->password = 'my_secure_password';  // 输出 "设置属性 'password' 为加密后的值"
echo $user->password;  // 获取加密后的密码

在设置属性值时进行验证或处理,例如加密密码、格式化日期等。
在获取属性时进行权限检查或其他逻辑控制。

  1. 实现对象的懒加载

使用 __get() 可以在第一次访问某个属性时延迟加载其值,这在需要节省资源或减少延迟加载的应用程序中很有用。

class LazyLoader {private $properties = [];private $loadedProperties = [];public function __get($name) {if (!isset($this->loadedProperties[$name])) {echo "延迟加载属性 '$name'\n";// 模拟从数据库或外部资源加载数据$this->properties[$name] = "Value for $name";$this->loadedProperties[$name] = true;}return $this->properties[$name];}
}$obj = new LazyLoader();
echo $obj->data;  // 输出 "延迟加载属性 'data'" 并显示 "Value for data"

当需要从数据库或远程服务加载数据时,只在属性第一次被访问时加载。
在大型对象或性能敏感的应用中减少初始化时间和内存占用。

  1. 实现对象的配置类

通过 __get() 和 __set() 方法,可以创建支持动态配置和访问的类

class Config {private $settings = [];public function __get($name) {echo "获取配置 '$name'\n";return $this->settings[$name] ?? null;}public function __set($name, $value) {echo "设置配置 '$name' 为 '$value'\n";$this->settings[$name] = $value;}
}$config = new Config();
$config->database = 'mysql';  // 输出 "设置配置 'database' 为 'mysql'"
echo $config->database;       // 输出 "获取配置 'database'" 并显示 "mysql"

设计一个简单的配置管理器,允许在程序运行时动态添加和修改配置。
适用于存储和访问应用程序设置、用户首选项等。

  1. 实现数据模型的属性映射

在 ORM(对象关系映射)或数据模型中,__get() 和 __set() 可以用来映射对象属性到数据库字段。

class DataModel {private $data = [];public function __get($name) {// 将属性名转换为数据库字段名或返回值$field = strtolower($name);echo "从数据库获取字段 '$field'\n";return $this->data[$field] ?? null;}public function __set($name, $value) {$field = strtolower($name);echo "设置字段 '$field' 为 '$value'\n";$this->data[$field] = $value;}
}$model = new DataModel();
$model->Name = 'John Doe';  // 输出 "设置字段 'name' 为 'John Doe'"
echo $model->Name;          // 输出 "从数据库获取字段 'name'" 并显示 "John Doe"

在 ORM 中,自动映射对象属性和数据库字段以减少手动代码编写。
在创建数据模型类时,使对象和数据源(如数据库表)之间的映射更加透明。

总结

这篇文章感觉怪怪的,因为写了那么多年代码很少用到这些魔术方法,还是在上学的时候用过(考试会考到),后来框架用多了就很少关注这些最基本的魔术方法

现在写的时候还需要去翻文档查资料,写着写着自己感觉到这些知识就很陌生,所以以后还是的常看啊,可能这也是我开始写技术学习的初衷,好记性不如烂笔头

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/60203.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PNG图片批量压缩exe工具+功能纯净+不改变原始尺寸

小编最近有一篇png图片要批量压缩,大小都在5MB之上,在网上找了半天要么就是有广告,要么就是有毒,要么就是功能复杂,整的我心烦意乱。 于是我自己用python写了一个纯净工具,只能压缩png图片,没任…

Axure网络短剧APP端原型图,竖屏微剧视频模版40页

作品概况 页面数量:共 40 页 使用软件:Axure RP 9 及以上,非软件无源码 适用领域:短剧、微短剧、竖屏视频 作品特色 本作品为网络短剧APP的Axure原型设计图,定位属于免费短剧软件,类似红果短剧、河马剧场…

Windows,虚拟机Ubuntu和开发板三者之间的NFS服务器搭建

Windows,虚拟机Ubuntu和开发板三者之间的NFS服务器搭建 (1)虚拟机 ubuntu 要使用桥接模式,不能使用其他模式 (2)通过网线将PC和开发板网口直连:这样的连接,开发板是无法连接外网的 (3&#xff…

C# 有趣的小程序—桌面精灵详细讲解

C# 桌面精灵详细讲解 最近写了一个简化版桌面精灵,效果如图所示,可以实现切换动画,说话、鼠标拖动,等功能。具体如何做,我发布了一个资源里面包含ppt详解、源代码以及动画素材。放心吧,免费的,…

视觉SLAM数学基础

本文系统梳理从相机成像模型,通过不同图像帧之间的构造几何约束求解位姿变换,再根据位姿变换和匹配点还原三维坐标的过程,可以作为基于特征点法的视觉SLAM的数学基础。 1、相机成像模型 1.1、针孔相机模型 实际相机的成像方式通常很复杂&a…

计算机新手练级攻略——如何搜索问题

目录 计算机学生新手练级攻略——如何搜索问题1.明确搜索意图2.使用精确关键词3.使用专业引擎搜索4.利用好技术社区1. Stack Overflow2. GitHub3. IEEE Xplore4. DBLP 5.使用代码搜索工具1. GitHub 代码搜索2. Stack Overflow 代码搜索3. Papers with Code4. IEEE Xplore 6.查阅…

51c自动驾驶~合集10

我自己的原文哦~ https://blog.51cto.com/whaosoft/11638131 #端到端任务 说起端到端,每个从业者可能都觉得会是下一代自动驾驶量产方案绕不开的点!特斯拉率先吹响了方案更新的号角,无论是完全端到端,还是专注于planner的模型&a…

大模型日报|6 篇必读的大模型论文

1.华为推出科学智能体 Agent K v1.0,已达 Kaggle 大师水平 在这项工作中,来自华为诺亚方舟实验室和伦敦大学学院的研究团队提出了 Agent K v1.0,它是一个端到端自主数据科学智能体(agent),旨在对各种数据科…

MySQL核心业务大表归档过程

记录一下2年前的MySQL大表的归档,当时刚到公司,发现MySQL的业务核心库,超过亿条的有7张表,最大的表有9亿多条,有37张表超过5百万条,部分表行数如下: 在测试的MySQL环境 : pt-archiv…

cache(二)直接缓存映射

在知乎发现一份不错得学习资料 请教CPU的cache中关于line,block,index等的理解? PPT 地址 https%3A//cs.slu.edu/%7Efritts/CSCI224_S15/schedule/chap6-cache-memory.pptx 课程主页 https://cs.slu.edu/~fritts/CSCI224_S15/schedule/ 0. 缓存定义 这张图展示了缓…

光流法(Optical Flow)

一、简介 光流法(Optical Flow)是一种用于检测图像序列中像素运动的计算机视觉技术。其基于以下假设: 1.亮度恒定性假设:物体在运动过程中,其像素值在不同帧中保持不变。 2.空间和时间上的连续性:相邻像素之…

打造自己的RAG解析大模型:(可商用)智能文档服务上线部署

通用版面分析介绍 版面解析是一种将文档图像转化为机器可读数据格式的技术,广泛应用于文档管理和信息提取等领域。通过结合OCR、图像处理和机器学习,版面解析能够识别文档中的文本块、图片、表格等版面元素,最终生成结构化数据,大…

【MySQL】MySQL基础知识复习(下)

前言 上一篇博客介绍了MySQL的库操作,表操作以及CRUD。 【MySQL】MySQL基础知识复习(上)-CSDN博客 本篇将进一步介绍CRUD操作,尤其是查找操作 目录 一.数据库约束 1.约束类型 1.1NULL约束 1.2UNIQUE:唯一约束 …

新的服务器Centos7.6 安卓基础的环境配置(新服务器可直接粘贴使用配置)

常见的基础服务器配置之Centos命令 正常来说都是安装一个docker基本上很多问题都可以解决了,我基本上都是通过docker去管理一些容器如:mysql、redis、mongoDB等之类的镜像,还有一些中间件如kafka。下面就安装一个 docker 和 nginx 的相关配置…

性能测试|JMeter接口与性能测试项目

前言 在软件开发和运维过程中,接口性能测试是一项至关重要的工作。JMeter作为一款开源的Java应用,被广泛用于进行各种性能测试,包括接口性能测试。本文将详细介绍如何使用JMeter进行接口性能测试的过程和步骤。 JMeter是Apache组织开发的基…

linux物理内存管理:node,zone,page

一、总览 对于物理内存内存,linux对内存的组织逻辑从上到下依次是:node,zone,page,这些page是根据buddy分配算法组织的,看下面两张图: 上面的概念做下简单的介绍: Node&#xff1a…

Pr:视频过渡快速参考(合集 · 2025版)

Adobe Premiere Pro 自带七组约四十多个视频过渡 Video Transitions效果,包含不同风格和用途,可在两个剪辑之间创造平滑、自然的转场,用来丰富时间、地点或情绪的变化。恰当地应用过渡可让观众更好地理解故事或人物。 提示: 点击下…

使用vscode 连接linux进行开发

1. 在Vscode中安装扩展功能remote ssh 2. 打开命令窗口 3. 在弹出的命令窗口输入ssh,并从弹出的提示中选择 Add New SSH Host 4. 在弹出的输入窗口中输入类似下面形式的 连接地址: 5. 输入回车后出现下面的对话框,这个对话框是说你要用哪个…

面试击穿mysql

Mysql三大范式: 第一范式(1NF): 不符合第一范式的典型情况是在一个字段中存放多种不同类型的详细信息。例如,在商品表中,若将商品名称、价格和类型都存储在同一个字段中,会带来诸多弊端。首先,在…

excel功能

统计excel中每个名字出现的次数 在Excel中统计每个名字出现的次数,您可以使用COUNTIF函数或数据透视表。以下是两种方法的详细步骤: 方法一:使用COUNTIF函数 准备数据:确保您的姓名列表位于一个连续的单元格区域,例如…