概念
一種程序設計範型,同時也是一種程序開發方法。將對象作爲程序基本單元,將程序和數據封裝其中,提供軟件的重用性、靈活性和可擴展性。屬性+方法;
對象的本
php使用一種zend_object_value結構體來存儲對象。
typedef struct _zend_object{
zend_class_entry *ce;//這裏是類入口
HashTable *properties;//屬性組成的hashtable
HashTable *guards;//protected from __get
}zend_object;
類聲明
一個文件只保存一個類,文件名包含類名,文件:類名.class.php或者類名.php
魔術方法的應用
__開頭、具有特殊作用的一些方法,PHP的語法糖。
__set():設置對象的不存在的屬性,自動調用__set();
__get():當獲取對象中不存在的屬性,會自動調用__get();
當給對象屬性賦值或者取值的時候,屬性不存在,也不會報錯,一定程度上增強了程序的健壯性。
__call($name, $arguments):當調用對象中不存在的方法,自動調用__call()這個方法;$name:表示的是調用的方法名稱。$arguments參數是一個數組包含要傳遞給方法的參數。
__callStatic():
MVC中如果控制器用了不存在的方法,那麼只要定義__call()魔術方法,就能友好的處理這種情況;
__toString()方法:
當打印echo出一個對象的時候,直接回調用__toString()這個方法,也就是打印出序列化的對象。
可以對__toString()進行自定義;
public function __toString(){
return "當前對象的用戶名,密碼是:";
}
echo本來可以打印一個對象的只是php對其做了限制,只有實現__toString後才允許使用。
繼承和多態
繼承和多態,對類的複用實現。一個是類級別的複用,一個是方法級別的複用。
類的組合與繼承
組合:在一個類中,某個屬性去實例化其他類,這個複用方式就是組合。
繼承:子類,父類的關係;
parent:表示父類;self:表示自身。使用::來調用父類的方法;
組合偏重整體與局部的關係,而繼承偏重父與子的關係;
耦合是一個軟件結構內不同模塊之間互聯程度的度量,不同模塊之間的依賴關係。
繼承存在問題:
1、繼承破壞封裝性。(有些對象不需要用到所有父類的方法)
2、繼承是緊耦合的。
3、繼承擴展複雜;
4、不恰當使用繼承可能違反現實世界中的邏輯。
慎重使用繼承:
專門用於被繼承的類,繼承樹的抽象層應該比較穩定,一般不要多於三層;
對於不是專門用於被繼承的類,禁止其被繼承,使用final修飾符。
優先考慮組合關係提高代碼的可重用性。
子類是擴展而不是覆蓋或者使父類的功能失效。
底層代碼多用組合,頂層/業務層代碼多用繼承。
各種語言中的多態
多態:同一類的對象收到相同消息時,會得到不同的結果,而這個消息是不可預測的。
多態:多種狀態,多種結果。
PHP作爲腳本語言,本身就是多態的。相同參數類型,得到不同的結果。調用相同的參數,返回不同結果。
<?php
class employee{
protected function working(){
echo '本方法需要重載';
}
}
class teacher extends employee{
public function working() {
echo '教書';
}
}
class coder extends employee{
public function working() {
echo '敲代碼';
}
}
function dopring($obj)
{
if(get_class($obj) == 'employee') {
echo 'error';
}else{
$obj->working();
}
}
dopring(new teacher());
dopring(new coder());
dopring(new employee());
面向接口編程
接口的作用:提供一套規範,所有用我這個接口的類就必須實現接口聲明的方法;
接口爲抽象而生。
<?php
interface mobile{
public function run();
}
class plain implements mobile{
public function run(){
echo '我是飛機';
}
public function fly() {
echo '我能飛行';
}
}
class car implements mobile{
public function run()
{
echo '我是汽車';
}
}
php5面向對象的特性做了很多增強,SPL標準PHP庫的嘗試。SPL中實現一些接口。接口是多重繼承的一種變相實現。
面向對象的設計準則
設計五大原則
單一職責原則
這是一個最簡單、最容易理解卻也是不容易做到的一個設計原則
避免相同的職責分散到不同類中,另一個需要避免一個類承擔太多職責
遵守SRP:(單一職責體現)
1、可以減少類之間的耦合
2、提高類的複用性
實例:
框架中的ORM模型編寫中的數據庫連接操作,工廠類負責抽象出來,不實現具體操作。
具體的操作在不同數據庫類中進行實現,根據傳入不同參數來判定不同的數據庫,並調用相關實現類。
命令請求者和命令實現者職責分離。
《敏捷軟件開發-原則方法與實踐》
接口隔離原則
設計應用程序如果一個模塊包含多個子模塊,需要小心處理模塊做抽象
接口隔離:ISP interface segregation principle
客戶端不應該被強迫實現一些他們不會使用的接口,應該把胖接口中的方法分組,然後用多個接口代替它。
每個接口服務於一個子模塊。
觀點:
1、一個類對另外一個類依賴性應該建立在最小接口上。
2、客戶端程序不應該依賴它不需要的接口方法
接口污染:
爲接口添加不必要的職責,如果接口中增加一個新功能目的減少接口實現類數量會到接口不斷被污染。
爲系統帶來維護和重用性差等方面問題。
接口隔離:定製化服務設計原則。(按需服務,實現多接口)接口既要拆但是也不能拆了太細。
高內聚:接口應該具備一些基本的功能,能獨自完成一個基本任務。
開放-封閉原則
開放:模塊的行爲必須是開放的、支持擴展的,而不是僵化的。
一個模塊在擴展性方面應該是開放的而在更改性方面應該是封閉的。
實例:
對外提供支付接口,必須保證接口的穩定性,同時又要使得接口是可擴展的。
思考對接口進行抽象:定義一個工廠類:負責實例化具體類,調用相關方法。
<?php
namespace app\pay\model;
/**
* @class 工廠-對接封裝了各個通道支付
* @param ins_type:要實例化通道的類文件
* @param data :支付接口參數
*/
class PayApi{
private $pay_ins = null;//支付通道實例
/**
*@function 初始化
*/
private function factory($pay_ins_type = '') {
if($this->pay_ins !== null) {//如果沒有實例化
return false;
}
$now_dir = rtrim(str_replace('\\', '/', dirname(__FILE__)), '/');
if(!is_file($now_dir.'/'.$pay_ins_type.'.php')) {
return false;
}
$class = "\\app\\pay\\model\\".$pay_ins_type;
$this->pay_ins = new $class();
return true;
}
/**
* @function 掃碼支付
*
*/
public function scan_code_pay($data = array(), $ins_type = '') {
if(!$this->factory($ins_type)) return return_error_mess('make_ins_fail');
return $this->pay_ins->scan_code_pay($data);//掃碼支付
}
}
具體實現方法可以放在具體的通道類:後續有新增通道只是需要實現其工廠類中的方法即可實現擴展。
class WeiZone {
private $fileCharset = 'UTF8';
private $pay_type = array('2');
private $url = 'http://notify_url';//微衆通知接口
/**
* @function 掃碼支付-具體實現類
*
*/
public function scan_code_pay($request = array()) {
if($request['pay_ver'] == '001') {
if(empty($request['chanel_info'])) return return_error_mess('chanel_info_null');
$chanel_info = json_decode($request['chanel_info'], true);
if(empty($chanel_info)) return return_error_mess('chanel_info_null');
...................
}else{
return return_error_mess('pay_ver_deny');
}
}
}
替換原則
由於面向對象中的繼承在具體編程中過於簡單,造成喜多系統設計濫用繼承或者錯誤了進行繼承等現象。
替換原則:LSP
子類必須能替換掉它們的父類,並出現在父類能夠出現的地方,合理進行繼承與派生,合理重用代碼。
PHP對於LSP的支持並不好。
<?php
abstract class Cache{
public abstract function set($key, $value, $expire=60);
public abstract function get($key);
public abstract function del($key);
public abstract function delAll($key);
public abstract function has($key);
}
依賴倒置原則
上層模塊不應該依賴於下層模塊,它們共同依賴於一個抽象(父類不能依賴於子類,它們都要依賴抽象類)
PHP並非一門好的面嚮對象語言,無法做到完全面向對象也無法優雅實現面向對象。一般大多使用精簡的MVC理論,比較少用設計模式。以類加代碼模塊的方式進行代碼組織。zend framework純面向對象的比較少。