8

我一直在网上搜索这个,但我似乎找不到足够清晰的东西让我理解。我在这里看到了关于 Java 的“类似”问题。

class animal{
    private $name;

    // traditional setters and getters
    public function setName($name){
        $this->name = $name;
    }

    public function getName(){
        return $this->name;
    }

    // animal constructors
    function __construct(){
       // some code here
    }

    // vs

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

$dog = new animal();
$dog->setName("spot");
echo $dog->getName();

// vs

$dog = new animal("spot");
  1. 我应该通过 setter 和 getter 还是通过构造函数声明和访问我的私有字段?
  2. 哪一个是最佳实践?
  3. 我了解构造函数的目的(也许不是),但是如果我可以通过 setter 和 getter 声明和访问我的私有字段,那么拥有构造函数的意义何在?

请注意...这是我第一次将 OOP 与 Web 开发和 PHP 一起使用,我正在尝试通过编写一些代码来“弄脏”我的双手来学习,以便我理解 OOP 中的某些内容。请保持简单。

4

6 回答 6

9

这更多的是语义问题,而不是每个说的最佳实践。

在您的示例中,您的业务逻辑可能会确定动物始终需要名称。所以用名字来构造对象是有意义的。如果您不想允许更改动物的名称,则不要编写 setter。

IE

class Animal 
{
    private $name;

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

    public function getName()
    {
        return $this->name;
    }
}

您可能具有动物不需要的其他属性,例如您只为它编写 getter/setter 的所有者

class Animal
{
    private $name;
    private $owner;

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

    public function getName()
    {
        return $this->name;
    }

    public function setOwner($owner)
    {
        $this->owner = $owner
    }
}

但是如果你发现你总是在同时创建一个动物和一个主人,你可能想把它放在承包商签名中以方便起见

class Animal
{
    private $name;
    private $owner;

    public function __construct($name, $owner = null)
    {    
        $this->name = $name;
        $this->owner = $owner;
    }

    public function getName()
    {
        return $this->name;
    }

    public function setOwner(Owner $owner)
    {
        $this->owner = $owner
    }

    public function getOwner()
    {
        return $this->owner;
    }
}

如果所有者是您的应用程序中的另一个类,您可以键入提示您的构造函数需要特定类型(类)的所有者。所有这些都是为了让您或其他开发人员更容易理解代码背后的一些要求/逻辑 - 以及可能在这里或那里发现错误

class Owner 
{
    private $name;

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

class Animal
{
    private $name;
    private $owner;

    public function __construct($name, Owner $owner = null)
    {    
        $this->name = $name;
        $this->owner = $owner;
    }

    public function getName()
    {
        return $this->name;
    }

    public function setOwner(Owner $owner)
    {
        $this->owner = $owner
    }

    public function getOwner()
    {
        return $this->owner;
    }
}

// Create a new owner!
$dave = new Owner('Farmer Dave');

// a standard php empty object
$otherObj = new \stdClass();

// Create a new animal
$daisy = new Animal('Daisy');

// Farmer dave owns Daisy
$daisy->setOwner($dave);

// Throws an error, because this isn't an instance of Owner
$daisy->setOwner($otherObj);

// Set up Maude, with Dave as the owner, a bit less code than before!
$maude = new Animal('Maude', $dave);
于 2012-07-31T12:44:45.667 回答
3

我应该通过 setter 和 getter 还是通过构造函数声明和访问我的私有字段?

在这种情况下,我问自己:

  • 为什么我要创建一个方法来保存一个单行函数?(+构造函数)

  • 重构两个、三个、四个、五个或更多 getter/setter 与一个构造函数相比会有多痛苦?(+构造函数)

  • 与一个构造函数相比,记录两个、三个、四个、五个或更多的 getter/setter 有多难?(+构造函数)

  • 是否会有记录的默认值?(+构造函数)

  • 我喜欢文档并希望人们阅读吗?(+构造函数)

  • 初始值会不确定吗?(+Setter)

  • 是否有一组等效形式(速记、国际、昵称)都可以被接受为所需参数的语法正确?(+二传手)

  • 是否有一组具有默认值的可选参数?(+二传手)

  • 是否普遍需要对初始值进行字符串化和解析?(+二传手)

  • 我不喜欢文档并期望人们进行实验吗?(+二传手)

哪一个是最佳实践?

Date对象似乎是大多数语言中最复杂的类,因此它的 PHP 实现将是最佳实践的一个很好的参考。

如果我可以通过 setter 和 getter 声明和访问我的私有字段,那么拥有构造函数有什么意义?

在对象实例化时隐式调用构造函数,以封装其类型的结果数据结构的默认状态。

CDD:上下文驱动开发角色 - 创建者、对象、行为

参考

于 2014-07-01T18:39:33.217 回答
2
  1. 依靠。通常有人说:如果是必需的依赖项,则使用构造函数,如果是可选的,则使用 getter/setter。
  2. 没有偏爱或反对其中之一。
  3. 构造函数包含在对象创建后立即执行的代码,它应该使对象处于稳定和可用的状态。这就是构造函数背后的想法,它在任何情况下都不起作用,但它应该给你一个想法,应该包含什么。

请注意,您甚至可以为同一属性同时实现构造函数参数和设置器,例如,如果您想允许稍后替换属性。

$bingo = new Dog;
echo $bingo->getName(); // DogHasNoNameException <-- maybe better as constructor argument?

$bingo = new Dog('Bingo');
echo $bingo->getName(); // "Bingo"
$spike = new Dog; // Missing argument 

$bingo->setName('Spike'); // Or maybe "rename()" ;)
echo bingo->getName(); // "Spike"
于 2012-07-31T12:37:34.707 回答
2

我应该通过 setter 和 getter 还是通过构造函数声明和访问我的私有字段?哪一个是最佳实践?

两个都。这取决于您的需求。如果在某些字段中需要一个值,您可以向 __construct()-Method 添加一个参数来执行此操作。或者你也可以添加一个可选的参数__construct给用户设置属性的选项

我了解构造函数的目的(也许不是),但是如果我可以通过 setter 和 getter 声明和访问我的私有字段,那么拥有构造函数的意义何在?

构造函数应该初始化你需要初始化的属性。

于 2012-07-31T12:40:21.153 回答
2

在我看来,写 setter's & getter's 更正确,从那时起,属性的数量只会增加。然后 __construct 可以获取键名(property => value)的属性数组,并将它们设置为属性。

于 2012-07-31T12:41:20.597 回答
1

1 > 那是你的选择:如果需要依赖,最好使用构造函数,否则,使用 getter。

2 > 最佳实践是第一位的,

实际上,你有一个名字,你的动物,但如果你添加一个类型和性别?并且你想分别调用 type、sexe 或 name,第一种方法比第二种方法好。

class animal{
private $name, $type, $sex;

// traditional setters and getters
public function setName($name){
    $this->name = $name;
}

public function setSex($sex){
    $this->sex = $sex;
}

public function setType($type){
    $this->type = $type;
}

public function getName(){
    return $this->name;
}

public function getSex(){
    return $this->sex;
}

public function getType(){
    return $this->type;
}

// animal constructors
function __construct(){
   // some code here
}

}

$dog = new animal();
$dog->setName("spot");
$dog->setSexe("male");
$dog->setType("dog");
echo $dog->getName().' is a '.$dog->getType().'('.dog->getSex().')';

3 > 这取决于第一个问题......但在全球范围内,我们总是需要一个依赖项,例如:

class animal{
private $name, $type, $sex;

// traditional setters and getters
public function setName($name){
    $this->name = $name;
}

public function setSex($sex){
    $this->sex = $sex;
}

private function setType($type){
    // if type is string ( cat, dog, lion ) and you want
    // to linked string in an id in your database (1, 2, 3...). 
    // you want to call your database connection ( declared in you constructor) 
    // and search type id here. 
    $this->type = $type;
}

public function getName(){
    return $this->name;
}

public function getSex(){
    return $this->sex;
}

public function getType(){
    return $this->type;
}

// animal constructors
public function __construct($type){
    // for sample you want to open your database here
    this->setType($type);
}

public function __destruct(){
    // and you want to close your connection here.
}

}
于 2012-07-31T12:50:57.160 回答