2010-03-09 125 views
9

說我有一個代表一個人的類,該類中的變量將是$ name。面向對象的PHP最佳實踐

以前,在我的劇本我會創建對象的實例,然後設置只要使用的名稱:

$object->name = "x"; 

然而,有人告訴我,這是不是最好的做法?我應該有一個函數set_name()或類似這樣的:

function set_name($name) 
{ 
    $this->name=$name; 
} 

這是正確的嗎?

如果在這個例子中我想插入一個新的「人」記錄到數據庫中,我如何將有關該人的所有信息(例如$ name,$ age,$ address,$ phone等)傳遞給該類插入它,我應該這樣做:

function set($data) 
{ 
    $this->name= $data['name']; 
    $this->age = $data['age']; 
    etc 
    etc 

} 

然後發送一個數組?這是最佳做法嗎?或者有人可以推薦最佳做法?

回答

21

對象上使用的性質明確的getter和setter方法(比如你給了set_name的例子),而不是直接訪問他們給你(其中包括)以下優點:

  • 你可以改變的內部'實現而不必修改任何外部呼叫。這種「外部」代碼不需要經常更改(因爲您提供了一致的訪問方式)。
  • 您非常明確地提供了哪些屬性可以在課堂外使用/調用。如果其他人開始使用你的課程,這將證明非常有用。

以上原因之一是,爲什麼這可能被認爲是最好的做法,雖然它不是真正必要這樣做(和可以被認爲矯枉過正,對於某些用途,例如,當你的目標是做很小的「處理」,但僅僅充當'數據'的佔位符)。

+0

使用getters/setters的另一個重要的事情是避免將所有方法都設置爲'public',以防止開發人員無法控制地更改/訪問它們。 – Strae 2010-03-09 12:01:56

2

作爲ChristopheD答案的對照,如果您的實例變量嚴格用於私人用途,那麼我不會爲編寫getter而設置私有實例變量。

如果其他對象需要訪問該對象,則可以隨時添加一個getter。使用的getter/setter也(這暴露了另一個問題,即其他類可能能夠改變getter返回的對象。但是,你的getter總是可以返回實例變量的副本

另外屏蔽同類其他部分瞭解其自己的實現,我發現它很有用!

6

我完全同意CristopheD(投了票)。我只是在創建新的時添加了一個很好的練習。

通常,使用構造函數接受必填字段併爲可選字段設置默認值。例如:

class Person 
{ 
    private $name; 
    private $surname; 
    private $sex; 

    // Male is the default sex, in this case 
    function Person($name, $surname, $sex='m'){ 
    $this->name = $name; 
    $this->surname = $surname; 
    $this->sex = $sex; 
    } 

    // Getter for name 
    function getName() 
    { 
    return $this->name; 
    } 

    // Might be needed after a trip to Casablanca 
    function setSex($sex) 
    { 
    $this->sex = $sex; 
    } 
} 

顯然,您可以在構造函數中使用setter方法(請注意sex setter的重複代碼)。

+4

「卡薩布蘭卡旅行後可能需要」LOL – Kirzilla 2010-03-09 11:49:55

+2

需要牢記的兩件事: 1. php 5+中的構造函數具有以下結構:__construct(){} 2.在php中,您不能創建兩個構造函數使用不同的簽名,如Person(String $ name)和Person(),您只能擁有一個簽名。 (雖然有很多方法可以實現這一點,但很容易。) – Nacho 2010-03-09 12:19:26

1

從更一般的觀點來看,直接訪問($ person-> name)和訪問器方法($ person-> getName)都被認爲是有害的。在OOP中,對象不應該分享關於其內部結構的任何知識,只執行發送給他們的消息。例如:

// BAD 

function drawPerson($person) { 
    echo $person->name; // or ->getName(), doesn't matter 
} 

$me = getPersonFromDB(); 
drawPerson($me); 

// BETTER 

class Person .... 
    function draw() { 
     echo $this->name; 
    } 

$me = getPersonFromDB(); 
$me->draw(); 

更多閱讀:http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html

29

你應該有二傳手/ getter方法。他們是一個痛苦,但你不一定要自己寫。只要您提供類成員,IDE(例如Eclipse或Netbeans)就可以自動爲您生成這些內容。但是,如果你不想在所有處理這個和你在PHP5,你可以使用它的魔力的方法來解決這個問題:

protected $_data=array(); 
    public function __call($method, $args) { 
     switch (substr($method, 0, 3)) { 
      case 'get' : 
       $key = strtolower(substr($method,3)); 
       $data = $this->_data[$key]; 
       return $data; 
       break; 
      case 'set' : 
       $key = strtolower(substr($method,3)); 
       $this->_data[$key] = isset($args[0]) ? $args[0] : null; 
       return $this; 
       break; 
      default : 
       die("Fatal error: Call to undefined function " . $method); 
     } 
    } 

該代碼將運行每次使用一個不存在的方法時,從設置開始或獲得。所以,你現在可以設置/獲取(和隱式聲明的)變量,像這樣:

$object->setName('Bob'); 
$object->setHairColor('green'); 

echo $object->getName(); //Outputs Bob 
echo $object->getHairColor(); //Outputs Green 

不需要聲明成員或setter/getter函數。如果將來您需要爲set/get方法添加功能,您只需聲明它,基本上覆蓋了魔術方法。 此外,由於setter方法返回$這個你可以chain他們像這樣:

$object->setName('Bob') 
     ->setHairColor('green') 
     ->setAddress('someplace'); 

這使得代碼既容易編寫和閱讀。

這種方法唯一的缺點是它讓你的班級結構更加難以辨別。由於實質上是在運行時聲明成員和方法,所以在執行期間必須轉儲對象以查看它包含的內容,而不是閱讀該類。 如果你的類需要聲明一個明確定義的接口(因爲它是一個庫,並且/或者你希望phpdoc生成API文檔),我強烈建議聲明公有的set/get方法以及上面的代碼。

+0

+1當我看到這個問題時,我立即想到了這些問題。好答案! – 2010-03-09 12:43:50

+0

這是一個有趣的技術。 – dmp 2010-03-09 15:01:47

+0

相信我,魔法吸氣劑/定型劑不值得這麼麻煩。 – 2012-09-06 05:33:01

4

要全程走OOP,你應該做類似的東西:

class User { 

private $_username; 
private $_email; 

public function getUsername() { 
    return $this->_username; 
} 
public function setUsername($p) { 
    $this->_username = $p; 
} 
... 
public function __construct() { 
    $this->setId(-1); 
    $this->setUsername("guest"); 
    $this->setEmail(""); 
} 
public function saveOrUpdate() { 
    System::getInstance()->saveOrUpdate($this); 
} 
} 

如果要保存用戶,您只需創建一個使用二傳手分配自己的價值觀,做$用戶> saveOrUpdate()方法,並有另一個類來處理所有的保存邏輯。