Getter and Setter?

2018-12-31 23:43发布

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):

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

15条回答
牵手、夕阳
2楼-- · 2019-01-01 00:01

Why use getters and setters?

  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.

direct assignment and getters/setters

查看更多
弹指情弦暗扣
3楼-- · 2019-01-01 00:02

This post is not specifically about __get and __set but rather __call which is the same idea except for method calling. As a rule, I stay away from any type of magic methods that allow for overloading for reasons outlined in the comments and posts HOWEVER, I recently ran into a 3rd-party API that I use which uses a SERVICE and a SUB-SERVICE, example:

http://3rdparty.api.com?service=APIService.doActionOne&apikey=12341234

The important part of this is that this API has everything the same except the sub-action, in this case doActionOne. The idea is that the developer (myself and others using this class) could call the sub-service by name as opposed to something like:

$myClass->doAction(array('service'=>'doActionOne','args'=>$args));

I could do instead:

 $myClass->doActionOne($args);

To hardcode this would just be a lot of duplication (this example very loosely resembles the code):

public function doActionOne($array)
    {
        $this->args     =   $array;
        $name           =   __FUNCTION__;
        $this->response =   $this->executeCoreCall("APIService.{$name}");
    }

public function doActionTwo($array)
    {
        $this->args     =   $array;
        $name           =   __FUNCTION__;
        $this->response =   $this->executeCoreCall("APIService.{$name}");
    }

public function doActionThree($array)
    {
        $this->args     =   $array;
        $name           =   __FUNCTION__;
        $this->response =   $this->executeCoreCall("APIService.{$name}");
    }

protected function executeCoreCall($service)
    {
        $cURL = new \cURL();
        return $cURL->('http://3rdparty.api.com?service='.$service.'&apikey='.$this->api.'&'.http_build_query($this->args))
                    ->getResponse();
    }

But with the magic method of __call() I am able to access all services with dynamic methods:

public function __call($name, $arguments)
    {
        $this->args     =   $arguments;
        $this->response =   $this->executeCoreCall("APIService.{$name}");   
        return $this;
    }

The benefit of this dynamic calling for the return of data is that if the vendor adds another sub-service, I do not have to add another method into the class or create an extended class, etc. I am not sure if this is useful to anyone, but I figured I would show an example where __set, __get, __call, etc. may be an option for consideration since the primary function is the return of data.


EDIT:

Coincidentally, I saw this a few days after posting which outlines exactly my scenario. It is not the API I was referring to but the application of the methods is identical:

Am I using api correctly?

查看更多
几人难应
4楼-- · 2019-01-01 00:03

You can use php magic methods __get and __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;
  }
}
?>
查看更多
妖精总统
5楼-- · 2019-01-01 00:07

Generally speaking, the first way is more popular overall because those with prior programming knowledge can easily transition to PHP and get work done in an object-oriented fashion. The first way is more universal. My advice would be to stick with what is tried and true across many languages. Then, when and if you use another language, you'll be ready to get something accomplished (instead of spending time reinventing the wheel).

查看更多
大哥的爱人
6楼-- · 2019-01-01 00:10

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.


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,

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.

查看更多
柔情千种
7楼-- · 2019-01-01 00:11

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

No getter and setter Optimizing PHP

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

  1. They are hard to debug.
  2. There is a negative performance impact.
  3. They require writing more code.

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

查看更多
登录 后发表回答