php 吸气剂和吸气剂?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4478661/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 13:08:42  来源:igfitidea点击:

Getter and Setter?

phpoopcoding-style

提问by Mark

I'm not a PHP developer, so I'm wondering if in PHP is more popular to use explicit getter/setters, in a pure OOP style, with private fields (the way I like):

我不是 PHP 开发人员,所以我想知道在 PHP 中是否更流行使用显式 getter/setter,以纯 OOP 风格,带有私有字段(我喜欢的方式):

class MyClass {
    private $firstField;
    private $secondField;

    public function getFirstField() {
        return $this->firstField;
    }
    public function setFirstField($x) {
        $this->firstField = $x;
    }
    public function getSecondField() {
        return $this->secondField;
    }
    public function setSecondField($x) {
        $this->secondField = $x;
    }
}

or just public fields:

或只是公共领域:

class MyClass {
    public $firstField;
    public $secondField;
}

Thanks

谢谢

回答by Dave

You can use php magic methods__getand __set.

您可以使用php 魔术方法__get__set.

<?php
class MyClass {
  private $firstField;
  private $secondField;

  public function __get($property) {
    if (property_exists($this, $property)) {
      return $this->$property;
    }
  }

  public function __set($property, $value) {
    if (property_exists($this, $property)) {
      $this->$property = $value;
    }

    return $this;
  }
}
?>

回答by Wiliam

Why use getters and setters?

为什么要使用 getter 和 setter?

  1. Scalability: It's easier refactor a getter than search all the var assignments in a project code.
  2. Debugging: You can put breakpoints at setters and getters.
  3. Cleaner: Magic functions are not good solution for writting less, your IDE will not suggest the code. Better use templates for fast-writting getters.
  1. 可扩展性:重构 getter 比搜索项目代码中的所有 var 分配更容易。
  2. 调试:您可以在 setter 和 getter 上放置断点。
  3. 更清洁:魔术函数不是写得少的好解决方案,您的 IDE 不会建议代码。更好地使用模板来快速编写 getter。

direct assignment and getters/setters

直接赋值和 getter/setter

回答by magallanes

Google already published a guide on optimization of PHP and the conclusion was:

谷歌已经发布了PHP优化指南,结论是:

No getter and setterOptimizing PHP

没有 getter 和 setter优化 PHP

And no, you must not use magic methods. For PHP, Magic Method are evil. Why?

不,你不能使用魔法方法。对于 PHP,Magic Method 是邪恶的。为什么?

  1. They are hard to debug.
  2. There is a negative performance impact.
  3. They require writing more code.
  1. 它们很难调试。
  2. 有负面的性能影响。
  3. 他们需要编写更多的代码。

PHP is not Java, C++, or C#. PHP is different and plays with different roles.

PHP 不是 Java、C++ 或 C#。PHP 是不同的,扮演着不同的角色。

回答by netcoder

Encapsulation is important in any OO language, popularity has nothing to do with it. In dynamically typed languages, like PHP, it is especially useful because there is little ways to ensure a property is of a specific type without using setters.

封装在任何面向对象语言中都很重要,与流行无关。在动态类型语言(如 PHP)中,它特别有用,因为几乎没有方法可以在不使用 setter 的情况下确保属性属于特定类型。

In PHP, this works:

在 PHP 中,这有效:

class Foo {
   public $bar; // should be an integer
}
$foo = new Foo;
$foo->bar = "string";

In Java, it doesn't:

在 Java 中,它不会:

class Foo {
   public int bar;
}
Foo myFoo = new Foo();
myFoo.bar = "string"; // error

Using magic methods (__getand __set) also works, but only when accessing a property that has lower visibility than the current scope can access. It can easily give you headaches when trying to debug, if it is not used properly.

使用魔术方法 ( __getand __set) 也有效,但仅当访问可见性低于当前范围可以访问的属性时。如果使用不当,在尝试调试时很容易让您头疼。

回答by Lorenz Lo Sauer

In addition to the already great and respected answers in here, I would like to expand on PHP having no setters/getters.

除了这里已经很好和受人尊敬的答案之外,我想扩展没有 setter/getter 的 PHP。

PHP does not have getter and setter syntax. It provides subclassed or magicmethods to allow "hooking" and overriding the property lookup process, as pointed out by Dave.

PHP 没有 getter 和 setter 语法。正如Dave所指出的,它提供了子类或魔术方法来允许“挂钩”和覆盖属性查找过程。

Magicallows us lazy programmersto do more with less code at a time at which we are actively engaged in a project and know it intimately, but usually at the expense of readability.

魔术允许我们这些懒惰的程序员在我们积极参与一个项目并密切了解它的时候用更少的代码做更多的事情,但通常以可读性为代价。

PerformanceEvery unnecessary function, that results from forcing a getter/setter-like code-architecture in PHP, involves its own memory stack-frame upon invocation and is wasting CPU cycles.

性能每一个不必要的函数,都是由在 PHP 中强制使用类似 getter/setter 的代码架构而产生的,在调用时涉及到它自己的内存堆栈帧,并且正在浪费 CPU 周期。

Readability:The codebase incurs bloating code-lines, which impacts code-navigation as more LOC mean more scrolling,.

可读性:代码库会产生膨胀的代码行,这会影响代码导航,因为更多的 LOC 意味着更多的滚动。

Preference:Personally, as my rule of thumb, I take the failure of static code analysis as a sign to avoid going down the magical road as long as obvious long-term benefits elude me at that time.

偏好:就我个人而言,作为我的经验法则,我将静态代码分析的失败视为避免走上神奇之路的标志,只要当时我无法获得明显的长期利益。

Fallacies:

谬论:

A common argument is readability. For instance that $someobject->widthis easier to read than $someobject->width(). However unlike a planet's circumferenceor width, which can be assumed to be static, an object's instance such as $someobject, which requires a width function, likely takes a measurement of the object's instance width.
Therefore readability increases mainly because of assertive naming-schemes and not by hiding the function away that outputs a given property-value.

一个常见的论点是可读性。例如,$someobject->width它比 更容易阅读$someobject->width()。然而,与行星的circumference或 不同width,可以假设为 static,对象的实例(例如 )$someobject需要宽度函数,可能会测量对象的实例宽度。
因此,可读性增加主要是因为断言的命名方案,而不是通过隐藏输出给定属性值的函数。

__get / __set uses:

__get / __set 使用:

  • pre-validation and pre-sanitation of property values

  • strings e.g.

    "
    some {mathsobj1->generatelatex} multi
    line text {mathsobj1->latexoutput}
    with lots of variables for {mathsobj1->generatelatex}
     some reason
    "
    

    In this case generatelatexwould adhere to a naming scheme of actionname + methodname

  • special, obvious cases

    $dnastringobj->homeobox($one_rememberable_parameter)->gattaca->findrelated()
    $dnastringobj->homeobox($one_rememberable_parameter)->gttccaatttga->findrelated()
    
  • 财产价值的预验证和预卫生

  • 字符串例如

    "
    some {mathsobj1->generatelatex} multi
    line text {mathsobj1->latexoutput}
    with lots of variables for {mathsobj1->generatelatex}
     some reason
    "
    

    在这种情况下,generatelatex将遵循 actionname + methodname 的命名方案

  • 特殊的、明显的情况

    $dnastringobj->homeobox($one_rememberable_parameter)->gattaca->findrelated()
    $dnastringobj->homeobox($one_rememberable_parameter)->gttccaatttga->findrelated()
    

Note:PHP chose not to implement getter/setter syntax. I am not claiming that getters/setter are generally bad.

注意:PHP 选择不实现 getter/setter 语法。我并不是说 getter/setter 通常是坏的。

回答by J-Rou

If you preffer to use the __call function, you can use this method. It works with

如果您更喜欢使用 __call 函数,则可以使用此方法。它与

  • GET => $this->property()
  • SET => $this->property($value)
  • GET => $this->getProperty()
  • SET => $this->setProperty($value)
  • 获取 => $this->property()
  • 设置 => $this->property($value)
  • 获取 => $this->getProperty()
  • 设置 => $this->setProperty($value)

kalsdas

卡尔斯达斯

public function __call($name, $arguments) {

    //Getting and setting with $this->property($optional);

    if (property_exists(get_class($this), $name)) {


        //Always set the value if a parameter is passed
        if (count($arguments) == 1) {
            /* set */
            $this->$name = $arguments[0];
        } else if (count($arguments) > 1) {
            throw new \Exception("Setter for $name only accepts one parameter.");
        }

        //Always return the value (Even on the set)
        return $this->$name;
    }

    //If it doesn't chech if its a normal old type setter ot getter
    //Getting and setting with $this->getProperty($optional);
    //Getting and setting with $this->setProperty($optional);
    $prefix = substr($name, 0, 3);
    $property = strtolower($name[3]) . substr($name, 4);
    switch ($prefix) {
        case 'get':
            return $this->$property;
            break;
        case 'set':
            //Always set the value if a parameter is passed
            if (count($arguments) != 1) {
                throw new \Exception("Setter for $name requires exactly one parameter.");
            }
            $this->$property = $arguments[0];
            //Always return the value (Even on the set)
            return $this->$name;
        default:
            throw new \Exception("Property $name doesn't exist.");
            break;
    }
}

回答by joas

class MyClass {
    private $firstField;
    private $secondField;
    private $thirdField;

    public function __get( $name ) {
        if( method_exists( $this , $method = ( 'get' . ucfirst( $name  ) ) ) )
            return $this->$method();
        else
            throw new Exception( 'Can\'t get property ' . $name );
    }

    public function __set( $name , $value ) {
        if( method_exists( $this , $method = ( 'set' . ucfirst( $name  ) ) ) )
            return $this->$method( $value );
        else
            throw new Exception( 'Can\'t set property ' . $name );
    }

    public function __isset( $name )
    {
        return method_exists( $this , 'get' . ucfirst( $name  ) ) 
            || method_exists( $this , 'set' . ucfirst( $name  ) );
    }

    public function getFirstField() {
        return $this->firstField;
    }

    protected function setFirstField($x) {
        $this->firstField = $x;
    }

    private function getSecondField() {
        return $this->secondField;
    }
}

$obj = new MyClass();

echo $obj->firstField; // works
$obj->firstField = 'value'; // works

echo $obj->getFirstField(); // works
$obj->setFirstField( 'value' ); // not works, method is protected

echo $obj->secondField; // works
echo $obj->getSecondField(); // not works, method is private

$obj->secondField = 'value'; // not works, setter not exists

echo $obj->thirdField; // not works, property not exists

isset( $obj->firstField ); // returns true
isset( $obj->secondField ); // returns true
isset( $obj->thirdField ); // returns false

Ready!

准备好!

回答by Emanuel Landeholm

Well, PHPdoes have magic methods __get, __set, __isset& __unset, which is always a start. Alas proper (get it?) OO properties is more than magic methods. The main problem with PHP's implementation is that magic methods are called for allinaccessible properties. Which means you have to Repeat Yourself (eg. by calling property_exists()) in the magic methods when determining if nameis actually a property of your object. And you can't really solve this general problem with a base class unless all your classes inherit from ie. ClassWithProperties, since PHP lacks multiple inheritance.

好吧,PHP确实有魔法方法__get, __set, __isset& __unset,这总是一个开始。唉(明白了吗?)OO 属性不仅仅是魔法方法。PHP 实现的主要问题是所有不可访问的属性都会调用魔术方法。这意味着在确定name是否实际上是对象的属性时,您必须在魔术方法中重复自己(例如,通过调用 property_exists())。除非您的所有类都继承自 ie,否则您无法真正用基类解决这个普遍问题。ClassWithProperties,因为 PHP 缺乏多重继承。

In contrast, Pythonnew style classes gives you property(), which lets you explicitly define all your properties. C#has special syntax.

相比之下,Python新样式类为您提供了property(),它可以让您显式定义所有属性。C#有特殊的语法。

http://en.wikipedia.org/wiki/Property_(programming)

http://en.wikipedia.org/wiki/Property_(编程)

回答by Sabaz

I made an experiment using the magic method __call. Not sure if I should post it (because of all the "DO NOT USE MAGIC METHODS" warnings in the other answers and comments) but i'll leave it here.. just in case someone find it useful.

我使用魔术方法 __call 做了一个实验。不确定我是否应该发布它(因为其他答案和评论中的所有“不要使用魔法方法”警告)但我会把它留在这里..以防万一有人觉得它有用。



public function __call($_name, $_arguments){
    $action  = substr($_name, 0, 4);
    $varName = substr($_name, 4);

    if (isset($this->{$varName})){
        if ($action === "get_") return $this->{$varName};
        if ($action === "set_") $this->{$varName} = $_arguments[0];
    }
}

Just add that method above in your class, now you can type:

只需在你的类中添加上面的方法,现在你可以输入:

class MyClass{
    private foo = "bar";
    private bom = "bim";
    // ...
    // public function __call(){ ... }
    // ...
}
$C = new MyClass();

// as getter
$C->get_foo(); // return "bar"
$C->get_bom(); // return "bim"

// as setter
$C->set_foo("abc"); // set "abc" as new value of foo
$C->set_bom("zam"); // set "zam" as new value of bom




This way you can get/set everything in your class if it exist so, if you need it for only a few specific elements, you could use a "whitelist" as filter.

通过这种方式,您可以获取/设置类中的所有内容(如果存在),如果您只需要几个特定元素,则可以使用“白名单”作为过滤器。

Example:

例子:

private $callWhiteList = array(
    "foo" => "foo",
    "fee" => "fee",
    // ...
);

public function __call($_name, $_arguments){
    $action  = substr($_name, 0, 4);
    $varName = $this->callWhiteList[substr($_name, 4)];

    if (!is_null($varName) && isset($this->{$varName})){
        if ($action === "get_") return $this->{$varName};
        if ($action === "set_") $this->{$varName} = $_arguments[0];
    }
}

Now you can only get/set "foo" and "fee".
You can also use that "whitelist" to assign custom names to access to your vars.
For example,

现在您只能获取/设置“foo”和“fee”。
您还可以使用该“白名单”来分配自定义名称以访问您的变量。
例如,

private $callWhiteList = array(
    "myfoo" => "foo",
    "zim" => "bom",
    // ...
);

With that list you can now type:

使用该列表,您现在可以键入:

class MyClass{
    private foo = "bar";
    private bom = "bim";
    // ...
    // private $callWhiteList = array( ... )
    // public function __call(){ ... }
    // ...
}
$C = new MyClass();

// as getter
$C->get_myfoo(); // return "bar"
$C->get_zim(); // return "bim"

// as setter
$C->set_myfoo("abc"); // set "abc" as new value of foo
$C->set_zim("zam"); // set "zam" as new value of bom


.
.
.
That's all.

.
.
.
就这样。



Doc:__call()is triggered when invoking inaccessible methods in an object context.

文档:在对象上下文中调用不可访问的方法时会触发__call()

回答by Manuel

After reading the other advices, I'm inclined to say that:

阅读其他建议后,我倾向于说:

As a GENERICrule, you will not always define setters for ALLproperties, specially "internal" ones (semaphores, internal flags...). Read-onlyproperties will not have setters, obviously, so some properties will only have getters; that's where __get() comes to shrink the code:

作为通用规则,您不会总是为所有属性定义 setter ,特别是“内部”属性(信号量、内部标志......)。显然,只读属性不会有 setter,所以有些属性只会有 getter;这就是 __get() 缩小代码的地方:

  • define a __get() (magical global getters) for all those properties which are alike,
  • group them in arrays so:
    • they'll share common characteristics: monetary values will/may come up properly formatted, dates in an specific layout (ISO, US, Intl.), etc.
    • the code itself can verify that only existing & allowed properties are being read using this magical method.
    • whenever you need to create a new similar property, just declare it and add its name to the proper array and it's done. That's way FASTERthan defining a new getter, perhaps with some lines of code REPEATED again and again all over the class code.
  • 为所有相似的属性定义一个 __get()(神奇的全局 getter),
  • 将它们分组为数组,以便:
    • 它们将具有共同的特征:货币价值将/可能会以正确的格式出现,特定布局(ISO、美国、国际)中的日期等。
    • 代码本身可以使用这种神奇的方法验证是否只读取了现有的和允许的属性。
    • 每当您需要创建一个新的类似属性时,只需声明它并将其名称添加到适当的数组中即可。这比定义一个新的 getter更快,也许在整个类代码中一遍又一遍地重复一些代码行。

Yes! we could write a private method to do that, also, but then again, we'll have MANY methods declared (++memory) that end up calling another, always the same, method. Why just not write a SINGLEmethod to rule them all...? [yep! pun absolutely intended! :)]

是的!我们也可以编写一个私有方法来做到这一点,但话又说回来,我们将声明许多方法(++memory),这些方法最终会调用另一个始终相同的方法。为什么不写一个单一的方法来统治他们......?[是的!双关语绝对是故意的!:)]

Magic setters can also respond ONLY to specific properties, so all date type properties can be screened against invalid values in one method alone. If date type properties were listed in an array, their setters can be defined easily. Just an example, of course. there are way too many situations.

Magic setter 也可以仅响应特定属性,因此可以单独使用一种方法针对无效值筛选所有日期类型属性。如果日期类型属性列在数组中,则可以轻松定义它们的设置器。当然只是一个例子。有太多的情况了。

About readability... Well... That's another debate: I don't like to be bound to the uses of an IDE (in fact, I don't use them, they tend to tell me (and forceme) how to write... and I have my likes about coding "beauty"). I tend to be consistent about naming, so using ctags and a couple of other aids is sufficient to me... Anyway: once all this magic setters and getters are done, I write the other setters that are too specific or "special" to be generalized in a __set() method. And that covers all I need about getting and setting properties. Of course: there's not always a common ground, or there are such a few properties that is not worth the trouble of coding a magical method, and then there's still the old good traditional setter/getter pair.

关于可读性……嗯……这是另一个争论:我不喜欢被 IDE 的使用所束缚(事实上,我不使用它们,他们倾向于告诉我(并强迫我)如何写……我喜欢编码“美”)。我倾向于在命名方面保持一致,因此使用 ctags 和其他一些辅助工具对我来说就足够了……无论如何:一旦完成所有这些神奇的 setter 和 getter,我就会编写其他过于具体或“特殊”的 setter在 __set() 方法中泛化。这涵盖了我需要的关于获取和设置属性的所有内容。当然:并不总是有共同点,或者有这么几个属性不值得为编写一个神奇的方法而烦恼,然后仍然存在古老的传统 setter/getter 对。

Programming languages are just that: human artificial languages. So, each of them has its own intonation or accent, syntax and flavor, so I won't pretend to write a Ruby or Python code using the same "accent" than Java or C#, nor I would write a JavaScript or PHP to resemble Perl or SQL... Use them the way they're meant to be used.

编程语言就是:人类人工语言。因此,它们中的每一个都有自己的语调或口音、语法和风格,所以我不会假装使用与 Java 或 C# 相同的“口音”来编写 Ruby 或 Python 代码,也不会编写 JavaScript 或 PHP 来类似Perl 或 SQL... 以它们应该使用的方式使用它们。