2010-03-09 128 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()方法,并有另一个类来处理所有的保存逻辑。