首頁 後端開發 php教程 簡述PHP提供的魔術方法

簡述PHP提供的魔術方法

Jun 09, 2018 am 10:26 AM
php

這篇文章主要介紹PHP中提供的魔術方法,有興趣的朋友參考下,希望對大家有幫助。

概述

在物件導向程式設計中,PHP提供了一系列的魔術方法,這些魔術方法為程式設計提供了許多便利。 PHP中的魔術方法通常以__(兩個底線)開始,不需要顯示的呼叫而是由某種特定的條件出發。

開始之前

在總結PHP的魔術方法之前先來定義兩個類,以便後邊範例使用:

程式碼如下:

<?php
class Device {
    public $name;           
    public $battery;        
    public $data = array(); 
    public $connection;     
 
    protected function connect() {
        $this->connection = &#39;resource&#39;;
        echo $this->name . &#39; connected&#39; . PHP_EOL;
    }
 
    protected function disconnect() {
        $this->connection = null;
        echo $this->name . &#39; disconnected&#39; . PHP_EOL;
    }
}
 
class Battery {
    private $charge = 0;
 
    public function setCharge($charge) {
        $charge = (int)$charge;
        if($charge < 0) {
            $charge = 0;
        }
        elseif($charge > 100) {
            $charge = 100;
        }
        $this->charge = $charge;
    }
}
?>


Device類別有四個成員屬性和兩個成員方法。 Battery類別有一個成員屬性和一個成員方法。

建構子和析構函式

建構子和析構函式分別在物件建立和銷毀時被呼叫。物件被「銷毀」是指不存在任何對該物件的引用,例如引用該物件的變數被刪除(unset)、重新賦值或腳本執行結束,都會呼叫析構函數。

__construct()

__construct()建構子是目前為止最常用的函式。在建立物件時,可以在建構函式中做一些初始化工作。可以為建構函式定義任多個參數,只要在實例化時傳入對應個數的參數即可。建構函式中出現的任何異常都會阻止物件的建立。

程式碼如下:

class Device {
   public function  __construct(Battery $battery, $name) {
       $this->battery = $battery;
       $this->name = $name;
       $this->connect();
    }
}

上面的範例程式碼中,Device類別的建構函式為成員屬性賦值並且呼叫了connect()方法。

將建構函數宣告為私有方法,可防止在類別外部建立對象,這在單利模式中經常使用。

__desctruct()

析構函數通常在物件被銷毀時調用,析構函數不接收任何參數。經常在析構函數中執行一些清理工作,例如關閉資料庫連線等。

屬性重載(Property Overloading)

有一點要注意的是:PHP中的」重載」與其他大多數語言的重載不是太一樣,雖然都實現了相同的功能。
屬性重載涉及到的兩個魔術方法主要是用來處理屬性訪問,定義了當我們嘗試訪問一個不存在(或不可訪問)的屬性時會發生什麼。

__get()

魔術方法__get()在我們嘗試存取一個不存在的屬性時會被呼叫。它接收一個參數,該參數表示存取屬性的名字,並且將該屬性的值傳回。在上面的Device類別裡,有一個data屬性,這個屬性就在這裡就起了作用,如下面得程式碼:

程式碼如下:

class Device {
    public function  __get($name) {
         if(array_key_exists($name, $this->data)) {
            return $this->data[$name];
        }
        return null;
    }
}

這個魔術方法最常用的地方就是透過建立一個「只讀」的屬性來擴展存取控制。在上面的Battery類別中,有一個私有屬性$charge,我們可以透過__get()魔術方法將該屬性擴展為在類別外部可讀但不能修改。程式碼如下:

程式碼如下:

class Battery {
    private $charge = 0;
 
    public function  __get($name) {
        if(isset($this->$name)) {
            return $this->$name;
        }
        return null;
    }
}

__set()

__set()魔術方法在我們嘗試修改一個無法存取的屬性時會被調用,它接收兩個參數,一個表示屬性的名字,一個表示屬性的值。範例程式碼如下:

程式碼如下:

class Device {
    public function  __set($name, $value) {
        // use the property name as the array key
        $this->data[$name] = $value;
    }
}

__isset()

__isset()魔術方法在對一個不可存取的屬性呼叫isset( )方法時會被調用,它接收一個參數,表示屬性的名字。它應該傳回一個布林值,用來表示該屬性是否存在。程式碼如下:

程式碼如下:

class Device {
    public function  __isset($name) {
        return array_key_exists($name, $this->data);
    }
}

__unset()

__unset()魔術方法在呼叫unset()函數銷毀一個不能存取的屬性時會被調用,它接收一個參數,表述屬性的名字。

物件轉換為字串

有時候我們需要將物件以字串的形式表現出來。如果我們直接列印一個對象,那麼程式將會輸出一個錯誤訊息:PHP Catchable fatal error: Object of class Device could not be converted to string

__toString()

#__toString()在我們將物件當作字串一樣使用時會被調用,它不接收任何參數。該方法允許我們定義物件的表現形式。程式碼如下:

程式碼如下:

class Device {
    public function  __toString() {
       $connected = (isset($this->connection)) ? &#39;connected&#39; : &#39;disconnected&#39;;
       $count = count($this->data);
       return $this->name . &#39; is &#39; . $connected . &#39; with &#39; . $count . &#39; items in memory&#39; . PHP_EOL;
    }
    ...
}

__set_state()(PHP 5.1)

靜態魔術方法__set_state(),在我們使用var_export ()函數輸出物件時會呼叫此方法。 var_export()函數用來將PHP變數轉換為PHP程式碼,它接收一個包含物件屬性值的關聯數組作為參數。範例程式碼如下:

程式碼如下:

class Battery {
    //...
    public static function  __set_state(array $array) {
        $obj = new self();
        $obj->setCharge($array[&#39;charge&#39;]);
        return $obj;
    }
    //...
}

複製物件

#

默认的,对象都是按引用传值的。因此,在将一个对象赋值给另一个变量时,只是创建了指向该对象的一个引用,并没有复制该对象。为了实现真正得复制一个对象,我们需要使用clone关键字。
这种“按引用传递”的策略同样适用于包含在对象内部的对象。即使我们克隆了一个对象,在对象内部的任何对象都不会被克隆,因此最终的结果是两个对象共享了同一个内部对象。示例代码如下:

代码如下:

$device = new Device(new Battery(), &#39;iMagic&#39;);
$device2 = clone $device;
 
$device->battery->setCharge(65);
echo $device2->battery->charge;
// 65

__clone()

__clone()魔术方法__clone()可以解决上面的问题。当对一个对象使用clone关键字时,该魔术方法会被调用。在这个魔术方法里,我们可以实现任何子对象的克隆,代码如下:

代码如下:

class Device {
    ...
    public function  __clone() {
        // copy our Battery object
        $this->battery = clone $this->battery;
    }
    ...
}

对象序列化

序列化是讲任意数据转换为字符串格式的过程。序列化通常用来将整个对象存入数据库或写入文件中。当反序列化存储的数据时,我们可以得到序列化之前的对象。但是,并不是所有得数据都可以被序列化,比如数据库连接。幸运的是,有一个魔术方法可以帮我们解决这个问题。

__sleep()

魔术方法__sleep()在对一个对象序列化时(调用serialize())会被调用。它不接收任何参数,而且应该返回一个包含所有应该被序列化的属性的数组。在该魔术方法中,也可以执行一些其他操作。
有一点要注意的是,不要再该函数中进行任何的析构操作,因为这可能会影响正在运行的对象。

示例代码如下:

代码如下:

class Device {
    public $name;           
    public $battery;       
    public $data = array();
    public $connection;    
    //...
    public function  __sleep() {
        return array(&#39;name&#39;, &#39;battery&#39;, &#39;data&#39;);
    }
    //...
}

__wakeup()

魔术方法__wakeup()在对存储的对象反序列化时会被调用。它不接收任何参数,也没有任何返回值。可以用它来处理在序列化时丢失的数据库连接或资源。代码如下:

代码如下:

class Device {
    //...
    public function  __wakeup() {
        // reconnect to the network
        $this->connect();
    }
    //...
}

方法重载

PHP还有两个与成员方法相关的魔术方法__call()和__callStatic(),这两个魔术方法类似于属性重载方法。

__call()

魔术方法__call()在调用不存在或不可访问的方法时会被调用。它接收两个参数,一个是调用的方法的名字,一个是包含函数参数的数组。我们可以使用这种方法调用子对象中得同名函数。

在这个例子中,要注意函数call_user_func_array(),这个函数允许我们动态调用一个命名的函数。

示例代码如下:

代码如下:

class Device {
    //...
    public function  __call($name, $arguments) {
        // make sure our child object has this method
        if(method_exists($this->connection, $name)) {
            // forward the call to our child object
            return call_user_func_array(array($this->connection, $name), $arguments);
        }
        return null;
    }
    //...
}

__callStatic()

魔术方法__callStatic()与__call()的功能一样,唯一不同的是,该方法在尝试访问一个不存在或不可访问的静态方法时会被调用。示例代码如下:

代码如下:

class Device {
    //...
    public static function  __callStatic($name, $arguments) {
        // make sure our class has this method
        if(method_exists(&#39;Connection&#39;, $name)) {
            // forward the static call to our class
            return call_user_func_array(array(&#39;Connection&#39;, $name), $arguments);
        }
        return null;
    }
    //...
}

将对象作为函数

有时候我们会需要将对象作为函数使用。将对象作为函数使用,就像我们使用其他普通的函数一样,可以传参。

__invoke()(PHP 5.3)

魔术方法__invoke()在尝试将对象作为函数使用时会被调用。在该方法中定义的任何参数,都将被作为函数的参数。示例代码如下:

代码如下:

class Device {
    //...
    public function __invoke($data) {
        echo $data;
    }
    //...
}
$device = new Device(new Battery(), &#39;iMagic&#39;);
$device(&#39;test&#39;);
// equiv to $device->__invoke(&#39;test&#39;)
// Outputs: test

其他:__autoload()

__autoload()方法并不是一个魔术方法,但是这个方法非常有用。但是,对着PHP版本的更新,该函数已经不建议使用,取而代之的是spl_auto_register()函数。

总结:以上就是本篇文的全部内容,希望能对大家的学习有所帮助。

相关推荐:

php针对数组的删除、转换、分组、排序

php针对文件操作及字符串加密的方法

php模拟post请求的三种常见用法

以上是簡述PHP提供的魔術方法的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

Rimworld Odyssey溫度指南和Gravtech
1 個月前 By Jack chen
初學者的Rimworld指南:奧德賽
1 個月前 By Jack chen
PHP變量範圍解釋了
4 週前 By 百草
在PHP中評論代碼
3 週前 By 百草
撰寫PHP評論的提示
3 週前 By 百草

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Laravel 教程
1604
29
PHP教程
1509
276
如何用PHP搭建社交分享功能 PHP分享接口集成實戰 如何用PHP搭建社交分享功能 PHP分享接口集成實戰 Jul 25, 2025 pm 08:51 PM

在PHP中搭建社交分享功能的核心方法是通過動態生成符合各平台要求的分享鏈接。 1.首先獲取當前頁面或指定的URL及文章信息;2.使用urlencode對參數進行編碼;3.根據各平台協議拼接生成分享鏈接;4.在前端展示鏈接供用戶點擊分享;5.動態生成頁面OG標籤優化分享內容展示;6.務必對用戶輸入進行轉義以防止XSS攻擊。該方法無需複雜認證,維護成本低,適用於大多數內容分享需求。

如何用PHP結合AI實現文本糾錯 PHP語法檢測與優化 如何用PHP結合AI實現文本糾錯 PHP語法檢測與優化 Jul 25, 2025 pm 08:57 PM

要實現PHP結合AI進行文本糾錯與語法優化,需按以下步驟操作:1.選擇適合的AI模型或API,如百度、騰訊API或開源NLP庫;2.通過PHP的curl或Guzzle調用API並處理返回結果;3.在應用中展示糾錯信息並允許用戶選擇是否採納;4.使用php-l和PHP_CodeSniffer進行語法檢測與代碼優化;5.持續收集反饋並更新模型或規則以提升效果。選擇AIAPI時應重點評估準確率、響應速度、價格及對PHP的支持。代碼優化應遵循PSR規範、合理使用緩存、避免循環查詢、定期審查代碼,並藉助X

超越燈堆:PHP在現代企業體系結構中的作用 超越燈堆:PHP在現代企業體系結構中的作用 Jul 27, 2025 am 04:31 AM

PHPisstillrelevantinmodernenterpriseenvironments.1.ModernPHP(7.xand8.x)offersperformancegains,stricttyping,JITcompilation,andmodernsyntax,makingitsuitableforlarge-scaleapplications.2.PHPintegrateseffectivelyinhybridarchitectures,servingasanAPIgateway

PHP中的對象關聯映射(ORM)性能調整 PHP中的對象關聯映射(ORM)性能調整 Jul 29, 2025 am 05:00 AM

避免N 1查詢問題,通過提前加載關聯數據來減少數據庫查詢次數;2.僅選擇所需字段,避免加載完整實體以節省內存和帶寬;3.合理使用緩存策略,如Doctrine的二級緩存或Redis緩存高頻查詢結果;4.優化實體生命週期,定期調用clear()釋放內存以防止內存溢出;5.確保數據庫索引存在並分析生成的SQL語句以避免低效查詢;6.在無需跟踪變更的場景下禁用自動變更跟踪,改用數組或輕量模式提升性能。正確使用ORM需結合SQL監控、緩存、批量處理和適當優化,在保持開發效率的同時確保應用性能。

用PHP和RabbitMQ建造彈性微服務 用PHP和RabbitMQ建造彈性微服務 Jul 27, 2025 am 04:32 AM

要構建彈性的PHP微服務,需使用RabbitMQ實現異步通信,1.通過消息隊列解耦服務,避免級聯故障;2.配置持久化隊列、持久化消息、發布確認和手動ACK以確保可靠性;3.使用指數退避重試、TTL和死信隊列安全處理失敗;4.通過supervisord等工具守護消費者進程並啟用心跳機制保障服務健康;最終實現系統在故障中持續運作的能力。

python run shell命令示例 python run shell命令示例 Jul 26, 2025 am 07:50 AM

使用subprocess.run()可安全執行shell命令並捕獲輸出,推薦以列表傳參避免注入風險;2.需要shell特性時可設shell=True,但需警惕命令注入;3.使用subprocess.Popen可實現實時輸出處理;4.設置check=True可在命令失敗時拋出異常;5.簡單場景可直接鍊式調用獲取輸出;日常應優先使用subprocess.run(),避免使用os.system()或已棄用模塊,以上方法覆蓋了Python中執行shell命令的核心用法。

VSCODE設置。 JSON位置 VSCODE設置。 JSON位置 Aug 01, 2025 am 06:12 AM

settings.json文件位於用戶級或工作區級路徑,用於自定義VSCode設置。 1.用戶級路徑:Windows為C:\Users\\AppData\Roaming\Code\User\settings.json,macOS為/Users//Library/ApplicationSupport/Code/User/settings.json,Linux為/home//.config/Code/User/settings.json;2.工作區級路徑:項目根目錄下的.vscode/settings

為PHP創建準備生產的Docker環境 為PHP創建準備生產的Docker環境 Jul 27, 2025 am 04:32 AM

使用正確的PHP基礎鏡像並配置安全、性能優化的Docker環境是實現生產就緒的關鍵。 1.選用php:8.3-fpm-alpine作為基礎鏡像以減少攻擊面並提升性能;2.通過自定義php.ini禁用危險函數、關閉錯誤顯示並啟用Opcache及JIT以增強安全與性能;3.使用Nginx作為反向代理,限制訪問敏感文件並正確轉發PHP請求至PHP-FPM;4.採用多階段構建優化鏡像,移除開發依賴,設置非root用戶運行容器;5.可選Supervisord管理多個進程如cron;6.部署前驗證無敏感信息洩

See all articles