php在物件導向部分有許多相關的魔術方法,這些方法為物件導向實作提供了便利,本文將詳細介紹魔術方法
大多數類別都有一種稱為建構子的特殊方法。當建立一個物件時,它將自動呼叫建構函數,通常用它執行一些有用的初始化任務
建構子的宣告與其它所操作的宣告一樣,只是其名稱必須是兩個下劃線__construct( )。這是PHP5中的變化;PHP4的版本中,建構子的名稱必須與類別名稱相同。為了向下相容,如果一個類別中沒有名為__construct( )的方法,PHP將搜尋一個與類別名稱相同的方法
void __construct ([ <span style="color: #0000ff;">mixed</span> <span style="color: #800080;">$args</span> [, $... ]] )
如果子類別中定義了建構子則不會隱式呼叫其父類別的建構子。要執行父類別的建構函數,需要在子類別的建構子中呼叫 parent::__construct()。如果子類別沒有定義建構函式則會如同一個普通的類別方法一樣從父類別繼承(假如沒有被定義為 private 的話)
<?<span style="color: #000000;">php </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> BaseClass { </span><span style="color: #0000ff;">function</span><span style="color: #000000;"> __construct() { </span><span style="color: #0000ff;">print</span> "In BaseClass constructor\n"<span style="color: #000000;">; } } </span><span style="color: #0000ff;">class</span> SubClass <span style="color: #0000ff;">extends</span><span style="color: #000000;"> BaseClass { </span><span style="color: #0000ff;">function</span><span style="color: #000000;"> __construct() { parent</span>::<span style="color: #000000;">__construct(); </span><span style="color: #0000ff;">print</span> "In SubClass constructor\n"<span style="color: #000000;">; } } </span><span style="color: #0000ff;">class</span> OtherSubClass <span style="color: #0000ff;">extends</span><span style="color: #000000;"> BaseClass { } </span><span style="color: #008000;">//</span><span style="color: #008000;"> In BaseClass constructor</span> <span style="color: #800080;">$obj</span> = <span style="color: #0000ff;">new</span><span style="color: #000000;"> BaseClass(); </span><span style="color: #008000;">//</span><span style="color: #008000;"> In BaseClass constructor // In SubClass constructor</span> <span style="color: #800080;">$obj</span> = <span style="color: #0000ff;">new</span><span style="color: #000000;"> SubClass(); </span><span style="color: #008000;">//</span><span style="color: #008000;"> In BaseClass constructor</span> <span style="color: #800080;">$obj</span> = <span style="color: #0000ff;">new</span><span style="color: #000000;"> OtherSubClass(); </span>?>
與構造方法相對的就是析構方法。析構方法是PHP5新加入的內容,在PHP4沒有析構方法。析構方法是在物件被銷毀之前自動呼叫的方法,主要執行一些特定的操作,例如關閉文件,釋放結果集等
與建構方法類似,一個類別的析構方法名稱必須是兩個下劃線 _ _destruct( )。析構函數不能帶有任何參數
<?<span style="color: #000000;">php </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> MyDestructableClass { </span><span style="color: #0000ff;">function</span><span style="color: #000000;"> __construct() { </span><span style="color: #0000ff;">print</span> "In constructor\n"<span style="color: #000000;">; </span><span style="color: #800080;">$this</span>->name = "MyDestructableClass"<span style="color: #000000;">; } </span><span style="color: #0000ff;">function</span><span style="color: #000000;"> __destruct() { </span><span style="color: #0000ff;">print</span> "Destroying " . <span style="color: #800080;">$this</span>->name . "\n"<span style="color: #000000;">; } } </span><span style="color: #008000;">//</span><span style="color: #008000;">In constructor Destroying MyDestructableClass</span> <span style="color: #800080;">$obj</span> = <span style="color: #0000ff;">new</span><span style="color: #000000;"> MyDestructableClass(); </span>?>
get()
讀取不可存取屬性(protected、private)時,__get()會被調用,並將屬性名以第一個參數(string)傳進此方法中
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">mixed</span> __get ( <span style="color: #0000ff;">string</span> <span style="color: #800080;">$name</span> )
<?<span style="color: #000000;">php </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> demo{ </span><span style="color: #0000ff;">protected</span> <span style="color: #800080;">$protected</span> = 1<span style="color: #000000;">; </span><span style="color: #0000ff;">public</span> <span style="color: #800080;">$public</span> = 2<span style="color: #000000;">; </span><span style="color: #0000ff;">private</span> <span style="color: #800080;">$private</span> = 3<span style="color: #000000;">; </span><span style="color: #0000ff;">function</span> __get(<span style="color: #800080;">$name</span><span style="color: #000000;">){ </span><span style="color: #0000ff;">echo</span> "111{<span style="color: #800080;">$name</span>}111<br>"<span style="color: #000000;">; } } </span><span style="color: #800080;">$d1</span> = <span style="color: #0000ff;">new</span><span style="color: #000000;"> demo; </span><span style="color: #800080;">$d1</span>-><span style="color: #0000ff;">protected</span>;<span style="color: #008000;">//</span><span style="color: #008000;">111protected111</span> <span style="color: #800080;">$d1</span>-><span style="color: #0000ff;">public</span><span style="color: #000000;">; </span><span style="color: #800080;">$d1</span>-><span style="color: #0000ff;">private</span>;<span style="color: #008000;">//</span><span style="color: #008000;">111private111</span> ?>
set()
在給不可存取屬性(protected、private)賦值時,__set() 會被調用,並將屬性名以第一個參數(string),值作為第二參數(mixed)傳入此方法中
<span style="color: #0000ff;">public</span> void __set ( <span style="color: #0000ff;">string</span> <span style="color: #800080;">$name</span> , <span style="color: #0000ff;">mixed</span> <span style="color: #800080;">$value</span> )
<?<span style="color: #000000;">php </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> demo{ </span><span style="color: #0000ff;">protected</span> <span style="color: #800080;">$protected</span> = 1<span style="color: #000000;">; </span><span style="color: #0000ff;">public</span> <span style="color: #800080;">$public</span> = 2<span style="color: #000000;">; </span><span style="color: #0000ff;">private</span> <span style="color: #800080;">$private</span> = 3<span style="color: #000000;">; </span><span style="color: #0000ff;">function</span> __set(<span style="color: #800080;">$name</span>,<span style="color: #800080;">$value</span><span style="color: #000000;">){ </span><span style="color: #0000ff;">echo</span> "0{<span style="color: #800080;">$name</span>}0{<span style="color: #800080;">$value</span>}<br>"<span style="color: #000000;">; } } </span><span style="color: #800080;">$d1</span> = <span style="color: #0000ff;">new</span><span style="color: #000000;"> demo; </span><span style="color: #800080;">$d1</span>-><span style="color: #0000ff;">protected</span> = '1';<span style="color: #008000;">//</span><span style="color: #008000;">0protected01</span> <span style="color: #800080;">$d1</span>-><span style="color: #0000ff;">public</span> = '2'<span style="color: #000000;">; </span><span style="color: #800080;">$d1</span>-><span style="color: #0000ff;">private</span> = '3';<span style="color: #008000;">//</span><span style="color: #008000;">0private03</span> ?>
isset()
當對不可存取屬性(protected、private)呼叫 isset() 或 empty() 時,__isset() 會被呼叫
<span style="color: #0000ff;">public</span> bool __isset ( <span style="color: #0000ff;">string</span> <span style="color: #800080;">$name</span> )
<?<span style="color: #000000;">php </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> demo{ </span><span style="color: #0000ff;">protected</span> <span style="color: #800080;">$protected</span> = 1<span style="color: #000000;">; </span><span style="color: #0000ff;">public</span> <span style="color: #800080;">$public</span> = 2<span style="color: #000000;">; </span><span style="color: #0000ff;">private</span> <span style="color: #800080;">$private</span> = 3<span style="color: #000000;">; </span><span style="color: #0000ff;">function</span> __isset(<span style="color: #800080;">$name</span><span style="color: #000000;">){ </span><span style="color: #0000ff;">echo</span> "0{<span style="color: #800080;">$name</span>}0<br>"<span style="color: #000000;">; } } </span><span style="color: #800080;">$d1</span> = <span style="color: #0000ff;">new</span><span style="color: #000000;"> demo; </span><span style="color: #0000ff;">empty</span>(<span style="color: #800080;">$d1</span>-><span style="color: #0000ff;">protected</span>);<span style="color: #008000;">//</span><span style="color: #008000;">0protected0</span> <span style="color: #0000ff;">empty</span>(<span style="color: #800080;">$d1</span>-><span style="color: #0000ff;">public</span><span style="color: #000000;">); </span><span style="color: #0000ff;">empty</span>(<span style="color: #800080;">$d1</span>-><span style="color: #0000ff;">private</span>);<span style="color: #008000;">//</span><span style="color: #008000;">0private0</span> ?>
unset()
當對不可存取屬性(protected、private)呼叫unset()時,__unset()會被呼叫
<span style="color: #0000ff;">public</span> void __unset ( <span style="color: #0000ff;">string</span> <span style="color: #800080;">$name</span> )
<?<span style="color: #000000;">php </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> demo{ </span><span style="color: #0000ff;">protected</span> <span style="color: #800080;">$protected</span> = 1<span style="color: #000000;">; </span><span style="color: #0000ff;">public</span> <span style="color: #800080;">$public</span> = 2<span style="color: #000000;">; </span><span style="color: #0000ff;">private</span> <span style="color: #800080;">$private</span> = 3<span style="color: #000000;">; </span><span style="color: #0000ff;">function</span> __unset(<span style="color: #800080;">$name</span><span style="color: #000000;">){ </span><span style="color: #0000ff;">echo</span> "0{<span style="color: #800080;">$name</span>}0<br>"<span style="color: #000000;">; } } </span><span style="color: #800080;">$d1</span> = <span style="color: #0000ff;">new</span><span style="color: #000000;"> demo; </span><span style="color: #0000ff;">unset</span>(<span style="color: #800080;">$d1</span>-><span style="color: #0000ff;">protected</span>);<span style="color: #008000;">//</span><span style="color: #008000;">0protected0</span> <span style="color: #0000ff;">unset</span>(<span style="color: #800080;">$d1</span>-><span style="color: #0000ff;">public</span><span style="color: #000000;">); </span><span style="color: #0000ff;">unset</span>(<span style="color: #800080;">$d1</span>-><span style="color: #0000ff;">private</span>);<span style="color: #008000;">//</span><span style="color: #008000;">0private0</span> ?>
clone()
在物件複製時會自動呼叫clone()方法,這方法不需要任何參數,可以透過該方法對克隆後的副本重新初始化
clone()方法會自動包含this和that兩個物件的引用,this是副本物件的引用,that是原本物件的引用
<?<span style="color: #000000;">php </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> Person{ </span><span style="color: #0000ff;">private</span> <span style="color: #800080;">$name</span><span style="color: #000000;">; </span><span style="color: #0000ff;">private</span> <span style="color: #800080;">$sex</span><span style="color: #000000;">; </span><span style="color: #0000ff;">private</span> <span style="color: #800080;">$age</span><span style="color: #000000;">; </span><span style="color: #0000ff;">function</span> __construct(<span style="color: #800080;">$name</span>="",<span style="color: #800080;">$sex</span>="",<span style="color: #800080;">$age</span>=1<span style="color: #000000;">){ </span><span style="color: #800080;">$this</span>->name= <span style="color: #800080;">$name</span><span style="color: #000000;">; </span><span style="color: #800080;">$this</span>->sex = <span style="color: #800080;">$sex</span><span style="color: #000000;">; </span><span style="color: #800080;">$this</span>->age = <span style="color: #800080;">$age</span><span style="color: #000000;">; } </span><span style="color: #0000ff;">function</span><span style="color: #000000;"> __clone(){ </span><span style="color: #800080;">$this</span>->name = <span style="color: #800080;">$this</span>->name."的副本"<span style="color: #000000;">; } </span><span style="color: #0000ff;">function</span><span style="color: #000000;"> say(){ </span><span style="color: #0000ff;">echo</span> "我的名字:" .<span style="color: #800080;">$this</span>->name.",性别:".<span style="color: #800080;">$this</span>->sex.",年龄:".<span style="color: #800080;">$this</span>->age."<br>"<span style="color: #000000;">; } } </span><span style="color: #800080;">$p1</span> = <span style="color: #0000ff;">new</span> Person('张三','男','20'<span style="color: #000000;">); </span><span style="color: #800080;">$p2</span> = <span style="color: #0000ff;">clone</span> <span style="color: #800080;">$p1</span><span style="color: #000000;">; </span><span style="color: #800080;">$p1</span>->say();<span style="color: #008000;">//</span><span style="color: #008000;">我的名字:张三,性别:男,年龄:20</span> <span style="color: #800080;">$p2</span>->say();<span style="color: #008000;">//</span><span style="color: #008000;">我的名字:张三的副本,性别:男,年龄:20</span> ?>
toString()
__toString()方法用於一個類別被當成字串時應怎樣回應,它是快速獲取物件的字串表示的最便捷的方式,是直接輸出物件引用時自動呼叫的方法
<?<span style="color: #000000;">php </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> TestClass { </span><span style="color: #0000ff;">public</span> <span style="color: #800080;">$foo</span><span style="color: #000000;">; </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> __construct(<span style="color: #800080;">$foo</span><span style="color: #000000;">) { </span><span style="color: #800080;">$this</span>->foo = <span style="color: #800080;">$foo</span><span style="color: #000000;">; } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span><span style="color: #000000;"> __toString() { </span><span style="color: #0000ff;">return</span> <span style="color: #800080;">$this</span>-><span style="color: #000000;">foo; } } </span><span style="color: #800080;">$class</span> = <span style="color: #0000ff;">new</span> TestClass('Hello'<span style="color: #000000;">); </span><span style="color: #0000ff;">echo</span> <span style="color: #800080;">$class</span>;<span style="color: #008000;">//</span><span style="color: #008000;">Hello</span> ?>
call()
在物件中呼叫一個不可存取方法時,__call()會被呼叫
callStatic()
在靜態上下文中呼叫一個不可存取方法時,__callStatic()會被呼叫
<?<span style="color: #000000;">php </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> MethodTest { </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> __call(<span style="color: #800080;">$name</span>, <span style="color: #800080;">$arguments</span><span style="color: #000000;">) { </span><span style="color: #0000ff;">echo</span> "Calling object method '<span style="color: #800080;">$name</span>' " . <span style="color: #008080;">implode</span>(', ', <span style="color: #800080;">$arguments</span>). "\n"<span style="color: #000000;">; } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">function</span> __callStatic(<span style="color: #800080;">$name</span>, <span style="color: #800080;">$arguments</span><span style="color: #000000;">) { </span><span style="color: #0000ff;">echo</span> "Calling static method '<span style="color: #800080;">$name</span>' " . <span style="color: #008080;">implode</span>(', ', <span style="color: #800080;">$arguments</span>). "\n"<span style="color: #000000;">; } } </span><span style="color: #800080;">$obj</span> = <span style="color: #0000ff;">new</span><span style="color: #000000;"> MethodTest; </span><span style="color: #008000;">//</span><span style="color: #008000;">Calling object method 'runTest' in object context</span> <span style="color: #800080;">$obj</span>->runTest('in object context'<span style="color: #000000;">); </span><span style="color: #008000;">//</span><span style="color: #008000;">Calling static method 'runTest' in static context</span> MethodTest::runTest('in static context'<span style="color: #000000;">); </span>?>
autoload()
在PHP5中,可以定義一個__autoload()函數,它會在試圖使用尚未被定義的類別時自動呼叫。透過呼叫此函數,腳本引擎在PHP出錯失敗前有了最後一個機會載入所需的類別
<?<span style="color: #000000;">php </span><span style="color: #0000ff;">function</span> __autoload(<span style="color: #800080;">$class_name</span><span style="color: #000000;">) { </span><span style="color: #0000ff;">require_once</span> <span style="color: #800080;">$class_name</span> . '.php'<span style="color: #000000;">; } </span><span style="color: #800080;">$obj</span> = <span style="color: #0000ff;">new</span><span style="color: #000000;"> MyClass1(); </span><span style="color: #800080;">$obj2</span> = <span style="color: #0000ff;">new</span><span style="color: #000000;"> MyClass2(); </span>?>
sleep()
在调用serialize()函数将对象串行化时,检查类中是否存在一个魔术方法 __sleep()。如果存在,该方法会先被调用,然后才执行序列化操作。此功能可以用于清理对象,并返回一个包含对象中所有应被序列化的变量名称的数组。如果该方法未返回任何内容,则 NULL 被序列化,并产生一个 E_NOTICE 级别的错误
__sleep()函数不需要接受任何参数,但需要返回一个数组,在数组中包含需要串行化的属性。未被包含在数组中的属性将在串行化时被忽略。如果没有在类中声明__sleep()方法,对象中的所有属性都将被串行化
wakeup()
在调用unserialize()函数将对象反串行化对象时,则会自动调用对象中的__wakeup()方法,用来在二进制串重新组成一个对象时,为新对象中的成员属性重新初始化
wakeup()经常用在反序列化操作中,例如重新建立数据库连接,或执行其它初始化操作
<?<span style="color: #000000;">php </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> Connection { </span><span style="color: #0000ff;">protected</span> <span style="color: #800080;">$link</span><span style="color: #000000;">; </span><span style="color: #0000ff;">private</span> <span style="color: #800080;">$server</span>, <span style="color: #800080;">$username</span>, <span style="color: #800080;">$password</span>, <span style="color: #800080;">$db</span><span style="color: #000000;">; </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> __construct(<span style="color: #800080;">$server</span>, <span style="color: #800080;">$username</span>, <span style="color: #800080;">$password</span>, <span style="color: #800080;">$db</span><span style="color: #000000;">) { </span><span style="color: #800080;">$this</span>->server = <span style="color: #800080;">$server</span><span style="color: #000000;">; </span><span style="color: #800080;">$this</span>->username = <span style="color: #800080;">$username</span><span style="color: #000000;">; </span><span style="color: #800080;">$this</span>->password = <span style="color: #800080;">$password</span><span style="color: #000000;">; </span><span style="color: #800080;">$this</span>->db = <span style="color: #800080;">$db</span><span style="color: #000000;">; </span><span style="color: #800080;">$this</span>-><span style="color: #000000;">connect(); } </span><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">function</span><span style="color: #000000;"> connect() { </span><span style="color: #800080;">$this</span>->link = <span style="color: #008080;">mysql_connect</span>(<span style="color: #800080;">$this</span>->server, <span style="color: #800080;">$this</span>->username, <span style="color: #800080;">$this</span>-><span style="color: #000000;">password); </span><span style="color: #008080;">mysql_select_db</span>(<span style="color: #800080;">$this</span>->db, <span style="color: #800080;">$this</span>-><span style="color: #000000;">link); } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span><span style="color: #000000;"> __sleep() { </span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">array</span>('server', 'username', 'password', 'db'<span style="color: #000000;">); } </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span><span style="color: #000000;"> __wakeup() { </span><span style="color: #800080;">$this</span>-><span style="color: #000000;">connect(); } } </span>?>
invoke()
当尝试以调用函数的方式调用一个对象时,__invoke()方法会被自动调用
<?<span style="color: #000000;">php </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> CallableClass { </span><span style="color: #0000ff;">function</span> __invoke(<span style="color: #800080;">$x</span><span style="color: #000000;">) { </span><span style="color: #008080;">var_dump</span>(<span style="color: #800080;">$x</span><span style="color: #000000;">); } } </span><span style="color: #800080;">$obj</span> = <span style="color: #0000ff;">new</span><span style="color: #000000;"> CallableClass; </span><span style="color: #800080;">$obj</span>(5);<span style="color: #008000;">//</span><span style="color: #008000;">int(5)</span> <span style="color: #008080;">var_dump</span>(<span style="color: #008080;">is_callable</span>(<span style="color: #800080;">$obj</span>));<span style="color: #008000;">//</span><span style="color: #008000;">bool(true)</span> ?>
【补充】
set_state()
当调用var_export()导出类时,set_state()方法会被调用,本方法的唯一参数是一个数组,其中包含按 array('property' => value, ...) 格式排列的类属性
[注意]var_export()返回关于传递给该函数的变量的结构信息,它和var_dump()类似,不同的是其返回的表示是合法的PHP代码,也就是说,var_export返回的代码,可以直接当作php代码赋给一个变量。 而这个变量就会取得和被var_export一样的类型的值
<?<span style="color: #000000;">php </span><span style="color: #0000ff;">class</span><span style="color: #000000;"> A { </span><span style="color: #0000ff;">public</span> <span style="color: #800080;">$var1</span><span style="color: #000000;">; </span><span style="color: #0000ff;">public</span> <span style="color: #800080;">$var2</span><span style="color: #000000;">; </span><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">function</span> __set_state(<span style="color: #800080;">$an_array</span><span style="color: #000000;">) { </span><span style="color: #800080;">$obj</span> = <span style="color: #0000ff;">new</span><span style="color: #000000;"> A; </span><span style="color: #800080;">$obj</span>->var1 = <span style="color: #800080;">$an_array</span>['var1'<span style="color: #000000;">]; </span><span style="color: #800080;">$obj</span>->var2 = <span style="color: #800080;">$an_array</span>['var2'<span style="color: #000000;">]; </span><span style="color: #0000ff;">return</span> <span style="color: #800080;">$obj</span><span style="color: #000000;">; } } </span><span style="color: #800080;">$a</span> = <span style="color: #0000ff;">new</span><span style="color: #000000;"> A; </span><span style="color: #800080;">$a</span>->var1 = 5<span style="color: #000000;">; </span><span style="color: #800080;">$a</span>->var2 = 'foo'<span style="color: #000000;">; </span><span style="color: #0000ff;">eval</span>('$b = ' . <span style="color: #008080;">var_export</span>(<span style="color: #800080;">$a</span>, <span style="color: #0000ff;">true</span>) . ';'<span style="color: #000000;">); </span><span style="color: #008000;">/*</span><span style="color: #008000;"> object(A)[2] public 'var1' => int 5 public 'var2' => string 'foo' (length=3) </span><span style="color: #008000;">*/</span> <span style="color: #008080;">var_dump</span>(<span style="color: #800080;">$b</span><span style="color: #000000;">); </span>?>