假设我有一个代表一个人的类,该类中的变量将是$ name。
以前,在我的脚本中,我会创建一个对象的实例,然后使用:
设置名称$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
}
然后发送一个数组?这是最好的做法吗?或者有人可以推荐最佳做法吗?
答案 0 :(得分:29)
你应该有setter / 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);
}
}
每次使用以set或get开头的不存在的方法时,此代码都会运行。所以你现在可以像这样设置/获取(并隐式声明)变量:
$object->setName('Bob');
$object->setHairColor('green');
echo $object->getName(); //Outputs Bob
echo $object->getHairColor(); //Outputs Green
无需声明成员或setter / getter函数。如果将来你需要为set / get方法添加功能,你只需声明它,基本上覆盖了魔术方法。 此外,由于setter方法返回$ this,你可以像chain那样:
$object->setName('Bob')
->setHairColor('green')
->setAddress('someplace');
使代码易于编写和读取。
这种方法的唯一缺点是它使你的类结构更难辨别。由于您基本上是在运行时声明成员和方法,因此您必须在执行期间转储对象以查看它包含的内容,而不是读取类。 如果你的类需要声明一个明确定义的接口(因为它是一个库和/或你希望phpdoc生成API文档),我强烈建议声明面向公众的set / get方法以及上面的代码。
答案 1 :(得分:21)
对对象的属性使用显式getter和setter(就像您为set_name
提供的示例)而不是直接访问它们,可以为您(以及其他)提供以下优势:
以上原因是为什么这可以被认为是最佳实践,尽管它并非真正必要这样做(并且可能被认为是某种用途的过度杀伤;例如当你的对象做很少的'处理时' '但仅仅充当'数据'的占位符。)
答案 2 :(得分: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方法(注意性别设置器的重复代码)。
答案 3 :(得分: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);
}
}
如果要保存用户,只需创建一个用户,使用Setters分配其值并执行$ user-> saveOrUpdate(),并使用另一个类来处理所有保存逻辑。
答案 4 :(得分:2)
作为对ChristopheD答案的对照,如果您的实例变量仅供私人使用,我不会费心去写一个getter& setter,只是将实例变量声明为private。
如果其他对象需要访问该对象,您始终可以添加一个getter。 (这暴露了另一个问题,因为其他类可能能够更改getter返回的对象。但是你的getter总是可以返回实例变量的 copy 。)
此外,使用getter / setter还可以保护同一类的其他部分不知道自己的实现,我偶尔发现它非常有用!
答案 5 :(得分: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