[TOC]
* * * * *
## 1 魔術方法的意義
php引擎將**類的相關接口**以魔術方法的形式暴露給用戶,
用戶可以通過**自定義相關接口**,實現靈活的功能組織
參考官方手冊分為**三類 **
>[info] 1 構造函數與析構函數
`__construct() __destruct()`
>[info] 2 重載
~~~
__set() __get() __isset() __unset()
__call() __callStatic()
~~~
>[info] 3 其他
~~~
__sleep() __wakeup() __invoke()
__toString() __set_state() __debugInfo
~~~
* * * * *
## 2 構造函數與析構函數
>[info] 1 構造函數 __construct()
在類中定義一個方法作為構造函數,
在每次創建新對象優先調用此方法,
通常完成對象的屬性設置等初始化工作
為了調用父類的構造函數,
需要在子類構造函數中調用parent::__construct()
子類沒有定義構造函數的會繼承父類的非private類構造函數
~~~
<?php
class BaseClass {
function __construct () {
print "In BaseClass constructor\n" ;
}
}
class SubClass extends BaseClass {
function __construct () {
parent :: __construct ();
print "In SubClass constructor\n" ;
}
}
class OtherSubClass extends BaseClass {
// inherits BaseClass's constructor
}
// In BaseClass constructor
$obj = new BaseClass ();
// In BaseClass constructor
// In SubClass constructor
$obj = new SubClass ();
// In BaseClass constructor
$obj = new OtherSubClass ();
?>
~~~
php4中使用與類名相同的方法名作為構造函數,
為了向后兼容,php5中查找__consrtuct()構造函數失敗時,會查找類同名構造函數,
命名空間中,與類名同名的方法不再作為構造函數
>[info] 2 析構函數__destruct()
類的對象的引用都被刪除或者對象被顯示銷毀時,
調用析構函數,進行清理工作
~~~
<?php
class MyDestructableClass {
function __construct () {
print "In constructor\n" ;
$this -> name = "MyDestructableClass" ;
}
function __destruct () {
print "Destroying " . $this -> name . "\n" ;
}
}
$obj = new MyDestructableClass ();
?>
~~~
調用父類的析構函數,
需要在子類的析構函數中顯示調用parent::__destruct()
子類如果自己沒有定義析構函數則會繼承父類的
析構函數在使用exit()終止腳本運行時也會被調用。
## 3 重載
傳統語言的重載是提供**同名的類方法的不同參數實現**,
而**php的重載是對不可訪問屬性和方法的動態實現**
PHP的重載指的是動態地設置類的屬性和方法,
與其他語言不通,php使用魔術方法實現重載
當調用未定義或不可見的類屬性或方法時,重載方法會被調用
大部分重載方法**只能在對象中進行**,(除__callStatic)必須聲明為public,
(除__callStatic)不可聲明為static,**參數不能使用引用傳遞**
>[info] 屬性重載
~~~
public void __set ( string $name , mixed $value )
public mixed __get ( string $name )
public bool __isset ( string $name )
public void __unset ( string $name )
~~~
給不可訪問屬性賦值時 `__set()`會被調用
讀取不可訪問屬性的值時,`__get()`會被調用
當對不可訪問屬性使用isset() empty()時,`__isset()`會被調用
當對不可訪問屬性調用unset()時,`__unset()`會被調用
~~~
<?php
class PropertyTest {
/** 被重載的數據保存在此 */
private $data = array();
/** 重載不能被用在已經定義的屬性 */
public $declared = 1 ;
/** 只有從類外部訪問這個屬性時,重載才會發生 */
private $hidden = 2 ;
public function __set ( $name , $value )
{
echo "Setting ' $name ' to ' $value '\n" ;
$this -> data [ $name ] = $value ;
}
public function __get ( $name )
{
echo "Getting ' $name '\n" ;
if ( array_key_exists ( $name , $this -> data )) {
return $this -> data [ $name ];
}
$trace = debug_backtrace ();
trigger_error (
'Undefined property via __get(): ' . $name .
' in ' . $trace [ 0 ][ 'file' ] .
' on line ' . $trace [ 0 ][ 'line' ],
E_USER_NOTICE );
return null ;
}
/** PHP 5.1.0之后版本 */
public function __isset ( $name )
{
echo "Is ' $name ' set?\n" ;
return isset( $this -> data [ $name ]);
}
/** PHP 5.1.0之后版本 */
public function __unset ( $name )
{
echo "Unsetting ' $name '\n" ;
unset( $this -> data [ $name ]);
}
/** 非魔術方法 */
public function getHidden ()
{
return $this -> hidden ;
}
}
echo "<pre>\n" ;
$obj = new PropertyTest ;
$obj -> a = 1 ;
echo $obj -> a . "\n\n" ;
var_dump (isset( $obj -> a ));
unset( $obj -> a );
var_dump (isset( $obj -> a ));
echo "\n" ;
echo $obj -> declared . "\n\n" ;
echo "Let's experiment with the private property named 'hidden':\n" ;
echo "Privates are visible inside the class, so __get() not used...\n" ;
echo $obj -> getHidden () . "\n" ;
echo "Privates not visible outside of class, so __get() is used...\n" ;
echo $obj -> hidden . "\n" ;
?>
~~~
輸出:
Setting 'a' to '1'
Getting 'a'
1Is 'a' set?
bool(true)
Unsetting 'a'
Is 'a' set?
bool(false)1Let's experiment with the private property named 'hidden':
Privates are visible inside the class, so __get() not used...
2
Privates not visible outside of class, so __get() is used...
Getting 'hidden'Notice: Undefined property via __get(): hidden in <file> on line 70 in <file> on line 29
* * * * *
>[info] 方法重載
~~~
public mixed __call ( string $name , array $arguments )
public static mixed __callStatic ( string $name , array $arguments )
~~~
在對象中調用一個不可訪問方法是 __call()會被調用
用靜態方式調用一個不可訪問方法__callStatic()會被調用
~~~
<?php
class MethodTest
{
public function __call ( $name , $arguments )
{
// 注意: $name 的值區分大小寫
echo "Calling object method ' $name ' "
. implode ( ', ' , $arguments ). "\n" ;
}
/** PHP 5.3.0之后版本 */
public static function __callStatic ( $name , $arguments )
{
// 注意: $name 的值區分大小寫
echo "Calling static method ' $name ' "
. implode ( ', ' , $arguments ). "\n" ;
}
}
$obj = new MethodTest ;
$obj -> runTest ( 'in object context' );
MethodTest :: runTest ( 'in static context' ); // PHP 5.3.0之后版本
?>
~~~
輸出:
Calling object method 'runTest' in object context
Calling static method 'runTest' in static context
## 4 其他
>[info] 1 __slepp() __wakeup()
~~~
public array __sleep ( void )
void __wakeup ( void )
~~~
`__sleep() `
serialize()序列化對象時,
會優先回調__sleep()方法
然后執行序列化
通常用于返回包含對象中所有應被序列化的變量名稱的數組。
如果該方法未返回內容,則NULL被序列化。
`__wakeup()`
unserialize()解序列化時,
會優先回調__wakeup()方法
然后執行解序列化
通常用來準備對象需要的資源
~~~
<?php
class Connection
{
protected $link ;
private $server , $username , $password , $db ;
public function __construct ( $server , $username , $password , $db )
{
$this -> server = $server ;
$this -> username = $username ;
$this -> password = $password ;
$this -> db = $db ;
$this -> connect ();
}
private function connect ()
{
$this -> link = mysql_connect ( $this -> server , $this -> username , $this -> password );
mysql_select_db ( $this -> db , $this -> link );
}
public function __sleep ()
{
return array( 'server' , 'username' , 'password' , 'db' );
}
public function __wakeup ()
{
$this -> connect ();
}
}
?>
~~~
>[info] 2 __invoke()
`mixed __invoke ([ $... ] )`
當以函數的方式調用一個對象時,
__invoke會被自動調用
~~~
<?php
class CallableClass
{
function __invoke ( $x ) {
var_dump ( $x );
}
}
$obj = new CallableClass ;
$obj ( 5 );
var_dump ( is_callable ( $obj ));
?>
~~~
輸出:
int(5)
bool(true)
* * * * *
>[info]3 __toString
`public string __toString ( void )`
echo $obj,輸出對象時的回調方法
必須返回一個字符串,否則發出致命錯誤
~~~
<?php
class TestClass
{
public $foo ;
public function __construct ( $foo )
{
$this -> foo = $foo ;
}
public function __toString () {
return $this -> foo ;
}
}
$class = new TestClass ( 'Hello' );
echo $class ;
?>
~~~
輸出:Hello
* * * * *
>[info] 4 __set_state()
`static object __set_state()`
使用var_export()導出類時,
此類靜態方法會被調用
~~~
<?php
class A
{
public $var1 ;
public $var2 ;
public static function __set_state ( $an_array ) // As of PHP 5.1.0
{
$obj = new A ;
$obj -> var1 = $an_array [ 'var1' ];
$obj -> var2 = $an_array [ 'var2' ];
return $obj ;
}
}
$a = new A ;
$a -> var1 = 5 ;
$a -> var2 = 'foo' ;
eval( '$b = ' . var_export ( $a , true ) . ';' );
// $b = A::__set_state(array(
// 'var1' => 5,
// 'var2' => 'foo',
// ));
var_dump ( $b );
?>
~~~
>[info] 5 __debuginfo()
`array __debugInfo ( void )`
使用var_dump()輸出對象的信息是時回調。
未定義的的輸出所有public protected屬性,
private屬性不會輸出
~~~
<?php
class C {
private $prop ;
public function __construct ( $val ) {
$this -> prop = $val ;
}
public function __debugInfo () {
return [
'propSquared' => $this -> prop ** 2 ,
];
}
}
var_dump (new C ( 42 ));
?>
~~~
輸出:
object(C)#1 (1) {
["propSquared"]=>
int(1764)
}
## 5 tp5中的魔術方法使用
- 更新記錄
- 概述
- 文件索引
- 函數索引
- 章節格式
- 框架流程
- 前:章節說明
- 主:(index.php)入口
- 主:(start.php)框架引導
- 主:(App.php)應用啟動
- 主:(App.php)應用調度
- C:(Controller.php)應用控制器
- M:(Model.php)數據模型
- V:(View.php)視圖對象
- 附:(App.php)應用啟動
- 附:(base.php)全局變量
- 附:(common.php)模式配置
- 附:(convention.php)全局配置
- 附:(Loader.php)自動加載器
- 附:(Build.php)自動生成
- 附:(Hook.php)監聽回調
- 附:(Route.php)全局路由
- 附:(Response.php)數據輸出
- 附:(Log.php)日志記錄
- 附:(Exception.php)異常處理
- 框架工具
- 另:(helper.php)輔助函數
- 另:(Cache.php)數據緩存
- 另:(Cookie.php)cookie操作
- 另:(Console.php)控制臺
- 另:(Debug.php)開發調試
- 另:(Error.php)錯誤處理
- 另:(Url.php)Url操作文件
- 另:(Loader.php)加載器實例化
- 另:(Input.php)數據輸入
- 另:(Lang.php)語言包管理
- 另:(ORM.php)ORM基類
- 另:(Process.php)進程管理
- 另:(Session.php)session操作
- 另:(Template.php)模板解析
- 框架驅動
- D:(\config)配置解析
- D:(\controller)控制器擴展
- D:(\model)模型擴展
- D:(\db)數據庫驅動
- D:(\view)模板解析
- D:(\template)模板標簽庫
- D:(\session)session驅動
- D:(\cache)緩存驅動
- D:(\console)控制臺
- D:(\process)進程擴展
- T:(\traits)Trait目錄
- D:(\exception)異常實現
- D:(\log)日志驅動
- 使用范例
- 服務器與框架的安裝
- 控制器操作
- 數據模型操作
- 視圖渲染控制
- MVC開發初探
- 模塊開發
- 入口文件定義全局變量
- 運行模式開發
- 框架配置
- 自動生成應用
- 事件與插件注冊
- 路由規則注冊
- 輸出控制
- 多種應用組織
- 綜合應用
- tp框架整合后臺auto架構快速開發
- 基礎原理
- php默認全局變量
- php的魔術方法
- php命名空間
- php的自動加載
- php的composer
- php的反射
- php的trait機制
- php設計模式
- php的系統時區
- php的異常錯誤
- php的輸出控制
- php的正則表達式
- php的閉包函數
- php的會話控制
- php的接口
- php的PDO
- php的字符串操作
- php的curl
- 框架心得
- 心:整體結構
- 心:配置詳解
- 心:加載器詳解
- 心:輸入輸出詳解
- 心:url路由詳解
- 心:模板詳解
- 心:模型詳解
- 心:日志詳解
- 心:緩存詳解
- 心:控制臺詳解
- 框架更新
- 4.20(驗證類,助手函數)
- 4.27(新模型Model功能)
- 5.4(新數據庫驅動)
- 7.28(自動加載)