變量復用
變量復用,適用于以下場景:1,整個項目公用的部分(比如errors);2,一組類要通信,或者同一個類的兩個函數之間要通信,通信數據可以用類來定義和約束;
場景1
所有錯誤相關的部分要放在一個類里面,方便查找和使用;
<?php class errors {const ERROR_PARAMS = 'params error';const ERROR_EMPTY_PARAM = 'empty param'; }class TestModel {public function run(){ $error = errors::ERROR_PARAMS;var_dump($error);return $error;} }$model = new TestModel(); $model->run();
解釋,errors是整個項目都可以訪問的,可以添加更多的錯誤消息在里面。
?
場景2:
同一個類的兩個函數中間需要通信,我們需要對這種通信定義一下數據結構。
<?php class DataMeta {public $mobile = '';public $message = ''; }class Sms {public function send($mobile, $message){ $data = new DataMeta();$data->mobile = $mobile;$data->message = $message;if ($this->checkValid($data)) {echo "Allow to send\n";} else {echo "Not allowed to send\n";} } public function checkValid(DataMeta $data){ if ($data->mobile && $data->message) {return true;} else {return false;}} }$model = new Sms(); $model->send(0, ''); $model->send(12345678910, 'my test');
checkValid函數對參數進行了校驗,我們使用了一個用于通信的數據類型DataMeta,里面包含了我們所需要的結構化數據。顯示定義DataMeta,是為了更好地理解。
當然使用DataMeta這個類型是有些弊端的,如果這個數據結構有很大的變動(比如字段名相同,但實際的含義已經變化了),那么用數組和注釋可能比DataMeta這樣的約束要更好一些。
總結下:
情況1,有一組數據,需要在函數間傳遞,并且結構不會有變化的;辦法是:可以定義一個MetaClass來約束這組數據。
情況2,有一組數據,需要在函數間傳遞,但是結構會經常性變化,則不能使用MetaClass來約束;辦法是:用數組和注釋來說明;特別地,Stdclass也適合這個場景;
情況3,有一組數據,需要在函數間傳遞,結構上只會新增字段,原始字段含義保持;辦法是:依然可以用MetaClass來約束。
?
以上解釋了PHP之間傳遞某個有結構約束的變量,可以有的方法。
除此之外,我們希望關心,有些類是完成類似的功能,也遵循一些共同的動作,這些類的函數名是一致的。
?
函數約束
函數約束的解決方案:1,基類派生類;2,接口interface。
如何區分哪種場景下使用基類派生類,哪種場景下使用interface。
我個人看法是:
1,如果能用接口實現最好優先使用接口,繼承盡量不要使用;
2,接口只定義約束,并不包含實現,所以各個類動作很不相同,只用接口來約束需要實現的函數即可(大多數的業務代碼就是很不同,用接口比較ok);
3,如果基類已經有完整的功能,派生類需要自己個性化完成的動作并不太多,使用基類繼承類。
代碼片段1:
實現interface時,未實現interface的函數,會報錯。所以使用interface時,定義的函數是必須實現的。
<?php interface SmsInterface {public function sendSms($abc); }class m1 implements SmsInterface {public function sendSms($aaa = 'cc'){var_dump(__CLASS__);} }class m2 implements SmsInterface {public function __construct(){var_dump(__CLASS__);} }$a = new m1(); $a->sendSms(); $b = new m2();
執行時,報錯:Fatal error: Class m2 contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (SmsInterface::sendSms) in
?
代碼片段2:
interface定義的函數不攜帶參數。
<?php interface SmsInterface { public function sendSms(); } class m1 implements SmsInterface {public function sendSms(){var_dump(__CLASS__);} } class m2 implements SmsInterface { public function __construct(){var_dump(__CLASS__);}public function sendSms(){var_dump(__CLASS__);} }$a = new m1(); $a->sendSms();$b = new m2(); $b->sendSms();
這段代碼,沒問題,可以正常執行。
?
代碼片段3:
如果interface的函數是攜帶參數的,那么實現類必須是和interface的函數原型保持一致,也需要攜帶參數才可以。
<?php interface SmsInterface {public function sendSms($mobile, $message); }class m1 implements SmsInterface {public function sendSms(){var_dump(__CLASS__);} }$a = new m1(); $a->sendSms();
執行時候報錯:Fatal error: Declaration of m1::sendSms() must be compatible with SmsInterface::sendSms($mobile, $message)
代碼片段4:
<?php interface SmsInterface {public function sendSms($mobile, $message); }class m1 implements SmsInterface {public function sendSms($mobile, $message){var_dump(__CLASS__);} }$a = new m1(); $a->sendSms(123, 'message');
這段代碼沒問題,可正常執行。
代碼片段5:
不再詳細展開,有興趣的自己動手實踐下之后的結論。
關于默認參數:
a,如果interface的函數有默認參數,實現類也必須實現自己的函數,所以interface的默認參數并不起作用;
b,實現類如果有默認參數,調用時候走默認參數邏輯沒問題;
關于參數列表不一致:
如果實現類的參數列表比interface定義的要少,是會報錯的;
如果實現類的參數列表比interface定義的要多,語法上不會報錯,也可以使用,另外的解決方案是setField()這樣的set函數;