前言:之前的一個同事換工作,在面試被問到了 PHP 的 trait 。因為沒用過, 所以沒答好,我大概是用過幾次的,想了想整理了以下的總結。
trait:trait 是在一些類(Class)的應該具備的特定的屬性或方法,而同父級的另外一些類應該避免包含這些屬性和方法情況下使用的.
當然, 這也和開發者對類的抽象能力有關, 有些抽象能力好的, 可以減少對 trait 的使用 但是這種情況應該是無法避免的 不然 trait 出現就毫無意義了.
還有一種情況, 就是使用 trait 的時候, 可以起到的約束開發者的作用, 提醒開發者注意需要在開發的過程中調用 trait 的某些屬性和方法.
同事則提出了一個好問題, 接口(interface) 不也是這個作用么?
不急, 讓我們先看個例子:
比如你要收集網站上各類數據, 開發了 Spider 類. Spider有個方法叫request()負責請求.
- namespaceXWSoul/Network;
- classSpider
- {
- publicfunctionrequest($url)
- {
- //do sth.
- }
- }
但是采集數據的過程中, 有些網站對蜘蛛敏感有些則不. 對于敏感的網站, 我們給出了一個使用代理的解決方案. 但是使用代理是會影響抓取速度的. 這就產生了 Spider 的子類有些需要用代理, 而能不用代理則盡量不用的情況.
于是這個時候我們新增了一個 trait Proxy:
- namespaceXWSoul/Network;
- trait Proxy
- {
- protected$isProxy= false;
- publicfunctionuseProxy($proxy)
- {
- //do sth proxy setups.
- $this->isProxy = true;
- return$this;
- }
- publicfunctionrequest($url)
- {
- if(!$this->isProxy) {
- thrownewException("Please using proxy.");
- }
- //do sth.
- returnparent::request($url);
- }
- }
trait 重寫了 Spider 的request()方法, 限定了在沒有調用代理的情況下調用會拋出異常.
回到之前的問題, trait 這樣的用法和 接口(interface) 有什么區別?
接口的約束是前置的是定義初始就必須實現的, 他可以約束方法的實現卻無法約束方法的調用, trait 是一種后置的調用, 他已經實現了方法, 關鍵的是, 他只對調用了自身的類產生約束(廢話一句), 而對沒有調用自身的類不產生影響(再一句廢話), 同時他是可復用的, 而且沒有破壞 Spider 類自身的實現增加, Spider 還是那個 Spider.
我想 trait 的用法再這里已經很有效了吧.
后話:
有人可能決定 另外實現一個 request 比如叫, proxyRequst 不就完了么? 你說的好有道理…然是如果我使用了不一樣的 代理具體對請求上有細節差異怎么辦呢? 在代碼里不停的 if if if 么? trait 如此清爽的方案 為何要放棄呢?
新聞熱點
疑難解答