Getter and Setter?

PhpOopCoding Style

Php Problem Overview


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

Php Solutions


Solution 1 - Php

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;
  }
}
?>

Solution 2 - Php

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

Solution 3 - Php

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 Methods 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 rules.

Solution 4 - Php

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.

In PHP, this works:

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

In Java, it doesn't:

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

Using magic methods (__get and __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.

Solution 5 - Php

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

  • GET => $this->property()
  • SET => $this->property($value)
  • GET => $this->getProperty()
  • SET => $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;
    }
}

Solution 6 - Php

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

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

Magic allows us lazy programmers to 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.

Performance Every 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.

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

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->width is easier to read than $someobject->width(). However unlike a planet's circumference or 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.

__get / __set uses:

  • 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 generatelatex would 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()
    

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

Solution 7 - Php

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!

Solution 8 - Php

Well, PHP does 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 all inaccessible properties. Which means you have to Repeat Yourself (eg. by calling property_exists()) in the magic methods when determining if name is 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.

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

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

Solution 9 - Php

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.

Solution 10 - Php

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

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

  • 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 FASTER than defining a new getter, perhaps with some lines of code REPEATED again and again all over the class code.

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 SINGLE method to rule them all...? [yep! pun absolutely intended! :)]

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.

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 force me) 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.

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.

Solution 11 - Php

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

Solution 12 - Php

There are many ways to create sourcecode in a netbeans-convention. This is nice. It makes thinks such easyer === FALSE. Just use the traditionel, specially if you are not sure which one of the properties should be encapsuled and which one not. I know, it is a boi.... pla... code, but for debugging-works and many other thinks it is the better, clear way. Dont spend to much time with thousend of arts how to make simple getters and setters. You cannot implement too some design patterns like the demeter-rule and so on, if you use magics. In specific situation you can use magic_calls or for small, fast and clear solutions. Sure you could make solutions for design-patters in this way too, but why to make you live more difficult.

Solution 13 - Php

Validating + Formatting/Deriving Values

Setters let you to validate data and getters let you format or derive data. Objects allow you to encapsulate data and its validation and formatting code into a neat package that encourages DRY.

For example, consider the following simple class that contains a birth date.

class BirthDate {

    private $birth_date;

    public function getBirthDate($format='Y-m-d') {
        //format $birth_date ...
        //$birth_date = ...
        return $birth_date;
    }

    public function setBirthDate($birth_date) {                   
        //if($birth_date is not valid) throw an exception ...          
        $this->birth_date = $birth_date;
    }

    public function getAge() {
        //calculate age ...
        return $age;
    }

    public function getDaysUntilBirthday() {
        //calculate days until birth days
        return $days;
    }
}

You'll want to validate that the value being set is

  • A valid date
  • Not in the future

And you don't want to do this validation all over your application (or over multiple applications for that matter). Instead, it's easier to make the member variable protected or private (in order to make the setter the only access point) and to validate in the setter because then you'll know that the object contains a valid birth date no matter which part of the application the object came from and if you want to add more validation then you can add it in a single place.

You might want to add multiple formatters that operate on the same member variable i.e. getAge() and getDaysUntilBirthday() and you might want to enforce a configurable format in getBirthDate() depending on locale. Therefore I prefer consistently accessing values via getters as opposed to mixing $date->getAge() with $date->birth_date.

getters and setters are also useful when you extend objects. For example, suppose your application needed to allow 150+ year birth dates in some places but not in others. One way to solve the problem without repeating any code would be to extend the BirthDate object and put the additional validation in the setter.

class LivingBirthDate extends BirthDate {

    public function setBirthDate($birth_date) {
        //if $birth_date is greater than 150 years throw an exception
        //else pass to parent's setter
        return parent::setBirthDate($birth_date);
    }
}

Solution 14 - Php

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:

https://stackoverflow.com/questions/36881224/am-i-using-api-correctly

Solution 15 - Php

Update: Don't use this answer since this is very dumb code that I found while I learn. Just use plain getter and setter, it's much better.


I usually using that variable name as function name, and add optional parameter to that function so when that optional parameter is filled by caller, then set it to the property and return $this object (chaining) and then when that optional parameter not specified by caller, i just return the property to the caller.

My example:

class Model
{
     private $propOne;
     private $propTwo;

     public function propOne($propVal = '')
     {
          if ($propVal === '') {
              return $this->propOne;
          } else {
              $this->propOne = $propVal;
              return $this;
          }
     }

     public function propTwo($propVal = '')
     {
          if ($propVal === '') {
              return $this->propTwo;
          } else {
              $this->propTwo = $propVal;
              return $this;
          }
     }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMarkView Question on Stackoverflow
Solution 1 - PhpDavis PeixotoView Answer on Stackoverflow
Solution 2 - PhpWiliamView Answer on Stackoverflow
Solution 3 - PhpmagallanesView Answer on Stackoverflow
Solution 4 - PhpnetcoderView Answer on Stackoverflow
Solution 5 - PhpJ-RouView Answer on Stackoverflow
Solution 6 - PhpLorenz Lo SauerView Answer on Stackoverflow
Solution 7 - PhpjoasView Answer on Stackoverflow
Solution 8 - PhpEmanuel LandeholmView Answer on Stackoverflow
Solution 9 - PhpSabazView Answer on Stackoverflow
Solution 10 - PhpManuelView Answer on Stackoverflow
Solution 11 - PhpAnthony RutledgeView Answer on Stackoverflow
Solution 12 - PhpDennis KomnenovicView Answer on Stackoverflow
Solution 13 - PhpFuzzyTreeView Answer on Stackoverflow
Solution 14 - PhpRasclattView Answer on Stackoverflow
Solution 15 - PhpajiyakinView Answer on Stackoverflow