【问题标题】:Magic getters and setters in Enterprise ArchitectEnterprise Architect 中的魔术 getter 和 setter
【发布时间】:2013-03-16 10:58:19
【问题描述】:

我正在使用 Enterprise Architect 制作 UML 类图并使用它生成 PHP5 代码。使用this,可以为属性创建getter 和setter,在代码中如下所示(仅显示相关行):

private $id;

public function getId()
{
    return $this->id;
}

/**
 * 
 * @param newVal
 */
public function setId($newVal)
{
    $this->id = $newVal;
}

我想使用魔术方法__get($property)__set($property, $value),而不是为每个属性使用单独的方法。有可能吗,如果有,怎么做?

对于 getter,它可能看起来像这样:

public function __get($property)
{
    switch ($property) {
        case 'id': return $this->id; break;
        default: return null;
    }
}

【问题讨论】:

  • 您的意思是是否以及如何告诉 ea 不要生成这些方法?
  • 不,我希望 EA 创建它们。
  • @Furgas 教会我私有或受保护的财产是一个很好的做法。为什么?例如:stackoverflow.com/a/8955492/1544337
  • @Furgas 这是个好主意!您可以将此添加为答案,我可能会接受它(尽管这是一种解决方法而不是答案),除非出现真实/更好的答案。

标签: php uml getter-setter enterprise-architect magic-methods


【解决方案1】:

这不是一个真正的答案,但您应该考虑是否希望这样做。这不会带来任何好处,但会导致 IDE 代码完成功能出现问题,实际上会使代码维护变得更加困难。在我看来,魔术 __get/__set 应该只用于动态属性,否则使用单独的 set/get 方法或使用公共属性。 This answer 总结得差不多了。

如果你还想走这条路,我会推荐simpler approach

【讨论】:

  • 您可以使用 PHPDoc 来提示您的 IDE 获取/设置属性;)
【解决方案2】:

我同意此页面上的其他人的观点,即这是一种不好的做法,您应该坚持使用普通的老式 getter 和 setter 方法而不是魔术方法。一旦您需要在访问器/修改器中进行验证或其他计算,您的开关/案例就会爆炸。维护是一团糟,而且对继承并不友好。具有魔法方法的子类在技术上会覆盖父类的魔法方法。

但是,您可以通过使用 EA 的代码模板编辑器修改代码模板来做到这一点。

引用Enterprise Architect User Guide on Code Templates:

代码模板使您能够自定义现有语言的代码生成。例如:

  • 修改生成新文件时创建的文件头
  • 更改生成代码的样式(例如缩进或大括号位置)以匹配所需的编码标准
  • 处理特定的刻板印象以生成专门的方法体和额外的方法。

还有:

Enterprise Architect 的基本代码模板指定了从 UML 元素到给定编程语言的各个部分的转换。模板以纯文本形式编写,其语法与标记语言和脚本语言相同。

这是代码编辑器的示例图片,其中加载了一些模板:

我不熟悉编辑器,也不熟悉他们使用的模板语言,因此我无法为您提供工作示例。但是我想如果你真的想修改模板,你可以从那里弄清楚。

【讨论】:

    【解决方案3】:

    你可以像这样实现一个通用的魔法 getter/setter:

    public function __get($name)
    {
        if (property_exists($this, $name))
            return $this->{$name};
        return null;
    }
    
    public function __set($name, $value)
    {
        if (property_exists($this, $name) && true/*Sanity checks here on $value instead of true if you want*/)
            $this->{$name} = $value;
    }
    

    但请记住这一点:

    这对于您的代码来说是一个真的糟糕的设计模式(即使它是符合 DRY 的做法)

    此外,此代码严格等同于公开您的所有属性,并且您不会因魔术方法而产生开销。 好消息是,如果您想对每个 setter 执行相同的健全性检查,您可以在那里进行。

    【讨论】:

    • 我可以在 Enterprise Architect 中手动添加这些功能,但是有没有办法让 EA自动生成它们?某个选项,某处?
    • 我真的不知道,因为我使用 Enterprise Architect 只用了几个小时就意识到使用它并不是一个那么的好主意。只是我的看法,我更喜欢设计我的类,代码可以通过许多其他方式生成。
    【解决方案4】:

    我想使用魔术方法 __get($property) 和 __set($property, $value) 而不是每个属性的单独方法。有没有可能,如果有,怎么做?

    不应该定义每个属性。一个简单的数组容器对他们来说就足够了。所以,这正是您正在寻找的:

    class Foo 
    {
       private $container = array();
    
       public function __set($property, $value)
       {
          $this->container[$property] = $value;
       }
    
       public function __get($property)
       {
           if (array_key_exists($property, $this->container)){
    
              return $this->container[$property];
    
           } else {
    
              trigger_error(sprintf('Undefined property "%s"', $property));
           } 
       }
    
    }
    
    $foo = new Foo();
    $foo->bar = "123";
    
    print $foo->bar; // prints 123
    
    $foo->id = "test string";
    
    print $foo->id; // test string
    
    print $foo->nonExistingProp; //issues E_NOTICE 
    

    如果你坚持使用访问器/修饰符,那么你只需要重载它们。使用__call()

    class Foo
    {
        private $container = array();
    
        public function __call($method, array $args)
        {
            $property = substr($method, 3);
    
            if (substr($method, 0, 3) == 'get'){
               // getter is being used
               if (isset($this->container[$property])){
                 return $this->container[$property];
               }
            }
    
            if (substr($method, 0, 3) == 'set'){
               //setter is being used
               $this->container[$property] = $args[0];
            }
        }
    }
    
    $foo = new Foo();
    
    $foo->setId('__BAR__');
    $foo->setStuff('__YEAH__'); 
    
    print $foo->getId(); // prints __BAR__
    print $foo->getStuff(); //prints __YEAH__
    

    【讨论】:

    • 这在我自己编写代码时会很有帮助,但我让 EA 生成它。你知道如何在 EA 中生成通用 getter/setter 吗?
    【解决方案5】:

    不知道你是用IDE开发还是纯记事本。因为你问的是那种类型的问题,我猜它是记事本。那么我建议你尝试众多免费 IDE 中的一个(我使用 NetBeans 已有一年了,其他人可能也对 Eclipse 感到满意)。

    如果您正在使用 EA 并做类模型,我猜您正在认真对待 OOP。如果是这样,您应该严格定义属性可见性,例如Zend Framework 2 忘记了 public property 可见性(也包括 staticpublic static 属性)。然后你最终会得到privateprotected 的属性,而getter/setter 的需求就在地球上。

    现在,如果您使用魔术__get()/__set() 方法,您将如何调试您的代码?一个人怎么知道在\One\Two\Three\Four 的类中发生了什么,属性为\First\Second\Third::$bang?它是如何设置的?为什么我得到的是这个值而不是另一个?

    另一方面 - 当使用遵循属性可见性的现代 IDE 时,请考虑这个类:

    Class A
    {
        private $foo;
        private $bar;
    
        protected $foobar;
    
        public function __get()
        {
            ...
        }
    
        public function __set()
        {
            ...
        }
    }
    

    没有setter 或getter。如果您正在编写您的代码,您的 IDE 不会提示您属性的名称(来自类外部),您必须将它们全部输入。使用 getter 和 setter(它们是公共方法,让您可以访问私有或受保护的属性)您可以使用代码提示并在使用现代 OOP 原则的同时加快您的开发过程。

    【讨论】:

    • 我提到我正在使用 Enterprise Architect 来生成我的代码。
    • 然后呢?我得到了它。我只是在解释,为什么可以使用 getter 和 setter 而不是您想要的,所以 EA 的输出是正确的。我没有得到-1,因为我没有写错……
    • 您的答案是有用的补充,但不是答案。我并不是说你对你投反对票是错的,我的意思是回答这个问题没有用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-22
    • 1970-01-01
    • 2018-05-11
    • 2011-10-05
    • 2015-08-05
    • 2016-10-20
    相关资源
    最近更新 更多