【问题标题】:Should I use C#-like property handling in PHP?我应该在 PHP 中使用类似 C# 的属性处理吗?
【发布时间】:2010-09-24 15:25:39
【问题描述】:

嗨,SO 社区, 我在这里看到:http://www.mustap.com/phpzone_post_203_setter-and-getter 使用的参数 一种 C# 通用的属性处理类型,即: 如果在 C# 中,您可以像这样定义一个类:

public class Person 
{
    private string _name;
    public string Name
    {
        get{ return _name; }
        set{ _name = value; }
    }
}

那么为什么在 php 中像这样定义类似的属性是明智的还是不明智的:

public class Person
{
    private var $name;    

    public function Name() 
    {
        if(func_num_args() == 0) {    return $this->name;  } 
        else {$this->name = func_get_arg(0);  }
    }
}

【问题讨论】:

  • 一个问题:为什么?通过普通的 getter/setter 语法(getName()setName($name))或魔术方法(让你做 $foo->name = 'bar'; echo $foo->name;)这样做的目的是什么?
  • Irwin - 这种语法不是 C# 所做的或看起来像的。类比不好。

标签: c# php oop


【解决方案1】:

IMO,这在 PHP 中看起来并不干净。这就像你试图将 C# 方式塞进 PHP 中,因为你认为它是 C# 的一个很好的特性。

我认为它是:在 PHP 中,您正在创建一个 函数 来做两件完全不同的事情,这没有意义。同时,在 C# 中,它是单个 property,被设计为设置/检索对象的单一访问点。

【讨论】:

  • 我的想法完全正确。在尝试将功能从一种语言移植到另一种语言之前,请三思而后行。 PHP 通过其神奇的方法处理 getter/setter 的苦差事。你可能想看看那些。
  • 是的,它违反了single responsibility principal(用于例程而不是类)。
  • 我相信在我的帖子中,只要你做的好,这个方法是可以实现的
【解决方案2】:

你违反了Single Responsibility Principle,因为你有一个函数既是getter又是setter。

在 c# 中它只是语法糖,并被转换为 getter 和 setter,就像你应该在 php 中编写它一样。

其实在c#中,可以通过写法进一步简化

public string Name { get; set; }

编译器会为你生成一个私有的支持字段,以及你的 getter 和 setter 函数。

【讨论】:

  • jQuery(一款出色的软件)一直都是这样做的。 x.html(foo) 设置值,x.html() 返回。
  • 这是一款很棒的软件,不过,他们有意识地决定打破 SRP,只有严格遵守他们的标准才能做到这一点。所有/大多数设置器(使用输入调用的方法)返回一个 jQuery 对象,它允许一个可链接的接口。吸气剂是无参数的……有时。 .attr('name') 之类的东西是 getter,.attr('name', value) 是 setter。这就是开始变得令人困惑的地方。因为它们的函数根据参数做不止一件事,所以库的使用者需要理解它。这可能会令人困惑。
【解决方案3】:

如果您需要对要设置的值进行一些额外检查,您可能需要定义 getFoosetFoo 方法,甚至更好地使用 property overloading。后者会给用户原生属性获取/设置的感觉。 (后者是你在 C# 中所做的。只是每个类只有一个方法,而不是很多。)

【讨论】:

  • +1,我还要提到重载仅模拟属性,但不会替换它们。 php 中的属性还没有真正的支持。
【解决方案4】:

这是明智的,例如:

class Settings
{
    private $data = array();

    public function __call($key,$arguments = array())
    {
        return !count($arguments)) ? $this->data[$key] : $this->data[$key] = $arguments[0];
    }
}

然后做

$Settings = new Settings();
$Settings->name('hello');
$Settings->foo('bar');

这现在已经创建了无限数量的可供使用的匿名函数,这通常使用 2 种方法构造,__get__set 这样您就可以定义方法和变量的分离, 示例如下

class Settings
{
    private $data = array();

    public function __set($key,$val)
    {
        $this->data[$key] = $val;
    }
    public function __get($key)
    {
        return $this->data[$key];
    }
}

这将允许您像这样设置变量:

$Settings->foo = 'bar';

但您可以更进一步,创建一个变量注册表系统:

所以基本上你可以将上面的类从 Settings 更改为 VariableStorage 并执行以下操作:

class User extends VariableStorage{}
class Profile extends VariableStorage{}

并像这样使用:

$Profile = new Profile('Robert','Pitt',USER_PRIV_ADMIN);
$Profile->id = 56;
$Profile->userdata = $Database->GetUserData($Profile); //Reads $Profile->id

因此您只需要定义一次方法,只要您将继承结构构建为一个好的设计,它就可以非常好地工作。

【讨论】:

  • 好的,你有一个“属性包”的实现(使用 any 名称附加属性)。一个有用的概念。我认为值得一提的是,这可以扩展为允许一组特定属性名称,方法是拥有一个带有私有静态字段的子类,该字段是一个有效属性名称的数组,并检查名称是否在该数组 - 拒绝任何其他属性名称。
【解决方案5】:

我个人在我的 PHP 中使用了类似的模式。我认为它很干净而且相当有用。

private $name;
public function name($name = null)
{
    if ($name === null) return $this->name;
    $this->name = $name;
}

您甚至可以这样做来强制执行某种类型安全:

private $name;
public function name(string $name = null)
{
    if ($name === null) return $this->name;
    $this->name = $name;
}

您还可以强制设置/获取引用而不是副本:

private $name;
public function &name(string &$name = null)
{
    if ($name === null) return $this->name;
    $this->name = &$name;
}

这是完全有效的 PHP,并且很好地模仿了 C#。

另外,Single Responsibility Principle 声明:

单一职责原则是一种计算机编程原则,它规定每个模块或类都应对软件提供的单个功能部分负责,并且该职责应完全由类封装。

因此,这并没有违反单一职责原则,因为这只是一个用于获取/设置类成员变量的类方法。

这里唯一的缺点是,在类的实例上,您必须调用函数来获取/设置成员变量,而不是真正的属性。您可以将此设计模式与 PHP 的 __get 和 __set 混合使用,但这只会增加开销。

【讨论】:

  • 次要问题:使用$name 作为参数名称会造成混淆。更合适的名称是$value
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-27
  • 1970-01-01
  • 2012-07-06
  • 2011-01-21
  • 1970-01-01
  • 2012-06-25
相关资源
最近更新 更多