用php實(shí)作一個(gè)簡(jiǎn)單的鍊式操作
Nov 30, 2016 pm 11:59 PM最近在讀《php核心技術(shù)與最佳實(shí)踐》這本書(shū),書(shū)中第一章提到用__call()方法可以實(shí)現(xiàn)一個(gè)簡(jiǎn)單的字符串鍊式操作,比如,下面這個(gè)過(guò)濾字符串然後再求長(zhǎng)度的操作,一般要這麼寫(xiě):
<span style="color: #008080;">strlen</span>(<span style="color: #008080;">trim</span>(<span style="color: #800080;">$str</span>));
那麼能否實(shí)現(xiàn)下面這種寫(xiě)法呢?
<span style="color: #800080;">$str</span>-><span style="color: #008080;">trim</span>()-><span style="color: #008080;">strlen</span>();
下面就來(lái)試試。
鍊式操作,說(shuō)白了其實(shí)就是鍊式的呼叫物件的方法。既然要實(shí)作字串的鍊式操作,那麼就要實(shí)作一個(gè)字串類(lèi),然後再對(duì)這個(gè)類(lèi)的物件進(jìn)行呼叫操作。我對(duì)字串類(lèi)別的期望如下:(1)當(dāng)我建立物件時(shí),我可以將字串賦值給物件的屬性,並且可以存取這個(gè)屬性讀取值;(2)我可以呼叫trim() 和strlen( )方法;(3)我還可以這麼呼叫方法$str->trim()->strlen()。
上面的第(1)條,是一個(gè)字串類(lèi)別的基本要求。先把這個(gè)實(shí)現(xiàn)了:
<span style="color: #008080;">1</span> <span style="color: #0000ff;">class</span> <span style="color: #0000ff;">String</span> <span style="color: #008080;">2</span> <span style="color: #000000;">{ </span><span style="color: #008080;">3</span> <span style="color: #0000ff;">public</span> <span style="color: #800080;">$value</span><span style="color: #000000;">; </span><span style="color: #008080;">4</span> <span style="color: #008080;">5</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> __construct(<span style="color: #800080;">$str</span>=<span style="color: #0000ff;">null</span><span style="color: #000000;">) </span><span style="color: #008080;">6</span> <span style="color: #000000;"> { </span><span style="color: #008080;">7</span> <span style="color: #800080;">$this</span>->value = <span style="color: #800080;">$str</span><span style="color: #000000;">; </span><span style="color: #008080;">8</span> <span style="color: #000000;"> } </span><span style="color: #008080;">9</span> }
可以試試看:
<span style="color: #008080;">1</span> <span style="color: #800080;">$str</span> = <span style="color: #0000ff;">new</span> <span style="color: #0000ff;">String</span>('01389'<span style="color: #000000;">); </span><span style="color: #008080;">2</span> <span style="color: #0000ff;">echo</span> <span style="color: #800080;">$str</span>->value;
然後再看第2條,先把$str->trim()實(shí)作了,參考書(shū)中的想法:觸發(fā)__call方法然後執(zhí)行call_user_func。程式碼如下:
<span style="color: #008080;"> 1</span> <span style="color: #0000ff;">class</span> <span style="color: #0000ff;">String</span> <span style="color: #008080;"> 2</span> <span style="color: #000000;">{ </span><span style="color: #008080;"> 3</span> <span style="color: #0000ff;">public</span> <span style="color: #800080;">$value</span><span style="color: #000000;">; </span><span style="color: #008080;"> 4</span> <span style="color: #008080;"> 5</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> __construct(<span style="color: #800080;">$str</span>=<span style="color: #0000ff;">null</span><span style="color: #000000;">) </span><span style="color: #008080;"> 6</span> <span style="color: #000000;"> { </span><span style="color: #008080;"> 7</span> <span style="color: #800080;">$this</span>->value = <span style="color: #800080;">$str</span><span style="color: #000000;">; </span><span style="color: #008080;"> 8</span> <span style="color: #000000;"> } </span><span style="color: #008080;"> 9</span> <span style="color: #008080;">10</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> __call(<span style="color: #800080;">$name</span>, <span style="color: #800080;">$args</span><span style="color: #000000;">) </span><span style="color: #008080;">11</span> <span style="color: #000000;"> { </span><span style="color: #008080;">12</span> <span style="color: #800080;">$this</span>->value = <span style="color: #008080;">call_user_func</span>(<span style="color: #800080;">$name</span>, <span style="color: #800080;">$this</span>->value, <span style="color: #800080;">$args</span>[0<span style="color: #000000;">]); </span><span style="color: #008080;">13</span> <span style="color: #0000ff;">return</span> <span style="color: #800080;">$this</span><span style="color: #000000;">; </span><span style="color: #008080;">14</span> <span style="color: #000000;"> } </span><span style="color: #008080;">15</span> }
測(cè)試下:
<span style="color: #008080;">1</span> <span style="color: #800080;">$str</span> = <span style="color: #0000ff;">new</span> <span style="color: #0000ff;">String</span>('01389'<span style="color: #000000;">); </span><span style="color: #008080;">2</span> <span style="color: #0000ff;">echo</span> <span style="color: #800080;">$str</span>-><span style="color: #008080;">trim</span>('0')->value;
結(jié)果如下:
上面要注意的是第12行:?$this->value = call_user_func($name, $this->value, $name, $this
->value函數(shù)的名字(這裡也就是trim),後面兩個(gè)是回呼函數(shù)(tirm)的參數(shù),參數(shù)的順序不要弄顛倒了。 $args是數(shù)組,也需要注意下。第2條還要實(shí)作strlen(),這時(shí)上面程式碼中的第13行就很關(guān)鍵了:?return $this;
?它的作用就是,在第12行呼叫trim()處理完字串後重新value屬性賦值,再傳回目前物件的引用,這樣物件內(nèi)的其他方法就可以對(duì)屬性value進(jìn)行連續(xù)運(yùn)算了,也就實(shí)作了鍊式運(yùn)算。 $str->strlen()實(shí)作如下:<span style="color: #008080;"> 1</span> <span style="color: #0000ff;">class</span> <span style="color: #0000ff;">String</span> <span style="color: #008080;"> 2</span> <span style="color: #000000;">{ </span><span style="color: #008080;"> 3</span> <span style="color: #0000ff;">public</span> <span style="color: #800080;">$value</span><span style="color: #000000;">; </span><span style="color: #008080;"> 4</span> <span style="color: #008080;"> 5</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> __construct(<span style="color: #800080;">$str</span>=<span style="color: #0000ff;">null</span><span style="color: #000000;">) </span><span style="color: #008080;"> 6</span> <span style="color: #000000;"> { </span><span style="color: #008080;"> 7</span> <span style="color: #800080;">$this</span>->value = <span style="color: #800080;">$str</span><span style="color: #000000;">; </span><span style="color: #008080;"> 8</span> <span style="color: #000000;"> } </span><span style="color: #008080;"> 9</span> <span style="color: #008080;">10</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> __call(<span style="color: #800080;">$name</span>, <span style="color: #800080;">$args</span><span style="color: #000000;">) </span><span style="color: #008080;">11</span> <span style="color: #000000;"> { </span><span style="color: #008080;">12</span> <span style="color: #800080;">$this</span>->value = <span style="color: #008080;">call_user_func</span>(<span style="color: #800080;">$name</span>, <span style="color: #800080;">$this</span>->value, <span style="color: #800080;">$args</span>[0<span style="color: #000000;">]); </span><span style="color: #008080;">13</span> <span style="color: #0000ff;">return</span> <span style="color: #800080;">$this</span><span style="color: #000000;">; </span><span style="color: #008080;">14</span> <span style="color: #000000;"> } </span><span style="color: #008080;">15</span> <span style="color: #008080;">16</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> <span style="color: #008080;">strlen</span><span style="color: #000000;">() </span><span style="color: #008080;">17</span> <span style="color: #000000;"> { </span><span style="color: #008080;">18</span> <span style="color: #0000ff;">return</span> <span style="color: #008080;">strlen</span>(<span style="color: #800080;">$this</span>-><span style="color: #000000;">value); </span><span style="color: #008080;">19</span> <span style="color: #000000;"> } </span><span style="color: #008080;">20</span> }
測(cè)試下:
<span style="color: #008080;">1</span> <span style="color: #800080;">$str</span> = <span style="color: #0000ff;">new</span> <span style="color: #0000ff;">String</span>('01389'<span style="color: #000000;">); </span><span style="color: #008080;">2</span> <span style="color: #0000ff;">echo</span> <span style="color: #800080;">$str</span>-><span style="color: #008080;">strlen</span>();
結(jié)果:
鍊式操作:
<span style="color: #0000ff;">echo</span> <span style="color: #800080;">$str</span>-><span style="color: #008080;">trim</span>('0')-><span style="color: #008080;">strlen</span>();
結(jié)果:
?
到這裡,這篇文章本來(lái)就結(jié)束了。但是,我想了下,其實(shí)不用__call()方法,也是可以實(shí)作鍊式運(yùn)算的。下面是不用__call()的實(shí)作:
<span style="color: #008080;"> 1</span> <span style="color: #0000ff;">class</span> <span style="color: #0000ff;">String</span> <span style="color: #008080;"> 2</span> <span style="color: #000000;">{ </span><span style="color: #008080;"> 3</span> <span style="color: #0000ff;">public</span> <span style="color: #800080;">$value</span><span style="color: #000000;">; </span><span style="color: #008080;"> 4</span> <span style="color: #008080;"> 5</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> __construct(<span style="color: #800080;">$str</span>=<span style="color: #0000ff;">null</span><span style="color: #000000;">) </span><span style="color: #008080;"> 6</span> <span style="color: #000000;"> { </span><span style="color: #008080;"> 7</span> <span style="color: #800080;">$this</span>->value = <span style="color: #800080;">$str</span><span style="color: #000000;">; </span><span style="color: #008080;"> 8</span> <span style="color: #000000;"> } </span><span style="color: #008080;"> 9</span> <span style="color: #008080;">10</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> <span style="color: #008080;">trim</span>(<span style="color: #800080;">$t</span><span style="color: #000000;">) </span><span style="color: #008080;">11</span> <span style="color: #000000;"> { </span><span style="color: #008080;">12</span> <span style="color: #800080;">$this</span>->value = <span style="color: #008080;">trim</span>(<span style="color: #800080;">$this</span>->value, <span style="color: #800080;">$t</span><span style="color: #000000;">); </span><span style="color: #008080;">13</span> <span style="color: #0000ff;">return</span> <span style="color: #800080;">$this</span><span style="color: #000000;">; </span><span style="color: #008080;">14</span> <span style="color: #000000;"> } </span><span style="color: #008080;">15</span> <span style="color: #008080;">16</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> <span style="color: #008080;">strlen</span><span style="color: #000000;">() </span><span style="color: #008080;">17</span> <span style="color: #000000;"> { </span><span style="color: #008080;">18</span> <span style="color: #0000ff;">return</span> <span style="color: #008080;">strlen</span>(<span style="color: #800080;">$this</span>-><span style="color: #000000;">value); </span><span style="color: #008080;">19</span> <span style="color: #000000;"> } </span><span style="color: #008080;">20</span> }
鍊式操作的關(guān)鍵是做完操作後要return $this。
另外,本文受到園子裡這篇文章的啟發(fā),用call_user_func_array()替換了call_user_func()實(shí)現(xiàn),將__call()方法修改如下。
<span style="color: #008080;">1</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">function</span> __call(<span style="color: #800080;">$name</span>, <span style="color: #800080;">$args</span><span style="color: #000000;">) </span><span style="color: #008080;">2</span> <span style="color: #000000;"> { </span><span style="color: #008080;">3</span> <span style="color: #008080;">array_unshift</span>(<span style="color: #800080;">$args</span>, <span style="color: #800080;">$this</span>-><span style="color: #000000;">value); </span><span style="color: #008080;">4</span> <span style="color: #800080;">$this</span>->value = <span style="color: #008080;">call_user_func_array</span>(<span style="color: #800080;">$name</span>, <span style="color: #800080;">$args</span><span style="color: #000000;">); </span><span style="color: #008080;">5</span> <span style="color: #0000ff;">return</span> <span style="color: #800080;">$this</span><span style="color: #000000;">; </span><span style="color: #008080;">6</span> }
與上面的__call()方法效果是相同的,這樣程式碼似乎比之前的實(shí)作更優(yōu)雅。
總結(jié):
__call()在物件呼叫一個(gè)不可存取的方法時(shí)會(huì)被觸發(fā),所以可以實(shí)作類(lèi)別的動(dòng)態(tài)方法的創(chuàng)建,實(shí)作php的方法重載功能,但它其實(shí)是一個(gè)語(yǔ)法糖(__construct()方法也是)。
那麼如果沒(méi)有__call()等語(yǔ)法糖,能否實(shí)現(xiàn)動(dòng)態(tài)方法的創(chuàng)建和鍊式操作呢?我想會(huì)涉及到以下幾個(gè)方面的問(wèn)題:類(lèi)別方法是否存在和可以調(diào)用,這個(gè)可以用method_exists、is_callable、get_class_methods等方法來(lái)實(shí)現(xiàn),另外,就是在創(chuàng)建對(duì)象時(shí)給屬性賦值(初始化),這個(gè)語(yǔ)法糖確實(shí)方便,不過(guò)不是必要的。等有時(shí)間再研究下吧。
?

熱AI工具

Undress AI Tool
免費(fèi)脫衣圖片

Undresser.AI Undress
人工智慧驅(qū)動(dòng)的應(yīng)用程序,用於創(chuàng)建逼真的裸體照片

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

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費(fèi)的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門(mén)文章

熱工具

記事本++7.3.1
好用且免費(fèi)的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強(qiáng)大的PHP整合開(kāi)發(fā)環(huán)境

Dreamweaver CS6
視覺(jué)化網(wǎng)頁(yè)開(kāi)發(fā)工具

SublimeText3 Mac版
神級(jí)程式碼編輯軟體(SublimeText3)