Just a simple question. I've seen many cases where the code is implemented like the following:
class User
{
private $id;
private $firstname;
private $lastname;
public function __construct() { some code }
public function getId() { return $this->id; }
public function getFirstname() { return $this->firstname; }
public function setFirstname($value) { $this->firstname = $value; }
}
// And properties are accessed like:
$user->getFirstname();
$user->getId();
So what is the reason of using private properties and having public getters, instead of making the properties public and accessing them directly like:
$user->firstname;
PS: Is it OK if I use the second method?
EDIT
Seems like I did not research well before asking this question (guess I used wrong keys to search on the topic). Here is another good answer to (almost) the same question: https://stackoverflow.com/a/1568230/1075534
Basically, for my case, one good reason to use getters and setters is to avoid changing 250 classes that directly access the property. So for example, imagine that I was not using a getter:
class User
{
public $firstname = 'abc';
public $lastname = 'cde';
}
$user = new User();
echo $user->firstname . ' ' . $user->lastname;
Now, imagine that I want to change the behavior of my app and I decide to print names as capitalized. In this case then I would search each implementation (250 in this case :) and capitalize the output wherever I called the properties. But, rather If I used a getter then I would just change the getter method:
class User
{
private $firstname = 'abc';
private $lastname = 'def';
public getFirstname()
{
return ucfirst(strtolower($this->firstname));
}
public getLastname()
{
return ucfirst(strtolower($this->lastname));
}
}
Also, bear in mind that a getter might not only gather information from a single property. Imagine the following:
class User
{
private $firstname = 'abc';
private $lastname = 'def';
public function getName()
{
return $this->firstname . ' ' . $this->lastname;
}
}
For those who still have questions on this matter, I suggest them reading the material that Gordon provided and especially the answer that I've linked.
Using Accessors satisfies the Uniform Access Principle.
Quoting Wikipedia:
The Uniform Access Principle was put forth by Bertrand Meyer. It states "All services offered by a module should be available through a uniform notation, which does not betray whether they are implemented through storage or through computation." This principle applies generally to object-oriented programming languages. In simpler form, it states that there should be no difference between working with an attribute, precomputed property, or method/query.
In his blog, Fowler explains
It effectively means that a client of the person should neither know nor care whether the age is stored or computed. This gives the person object the flexibility to change between the two easily as well as removing what is usually an unnecessary concern from the client. It's an important part of encapsulation - or at least the data-hiding aspect of encapsulation.
To illustrate the point, imagine a class like this:
class Now
{
public $timestamp;
public function getTomorrow()
{
return strtotime('+1 day', $this->timestamp);
}
// … more code
When you do it this way, you are forcing the developer using that class to know the implementation details. To get the now's timestamp, the developer has to do
echo $now->timestamp;
whereas to get the computed timestamp for tomorrow, the developer has to do
echo $now->getTomorrow();
But the developer shouldn't need to care, so if you want to follow the UAP, you will provide an Accessor to get the timestamp. And funnel all access through methods.
Doing so also has the additional benefit of a more stable API. Imagine you need to change the implementation detail later in the project and turn timestamp into a DateTime object. Your class now looks like this:
class Now
{
public $dateTime; // <-- no longer just a timestamp
public function getTomorrow()
{
return strtotime('+1 day', $this->dateTime->getTimestamp());
}
// … more code
Now any developer that previously used $now->timestamp will have to change their consuming code to accomodate for that change. Whereas when you had used a Getter right from the start, it wouldn't be a problem at all, because the Getter would have made sure that it returned the timestamp. To further prove that point, note how the developer would not have to change anything to consume getTomorrow(). Although internally we changed the details, the public API still behaves the same.
Note that UAP is just a guideline. Modern IDEs make it dirt easy to generate Accessors and Mutators for you, so it's easy to follow. But it's not an absolute truth. If you can reasonably justify not following it, then don't follow it and use public properties. But it should be an informed decision.
However, in general, you want to avoid Getters (and Setters) anyway and just tell your objects what to do. This will give a much slimmer API. If your API has lots and lots of Getters, chances are you are scattering code that really should be inside the object into the consumers.
When a variable is declared public, it is accessible from any class making it easier for you as a programmer to use; thus explaining your desire to use the second method you described. However, some variables need to be declared private for security reasons (also it is sometimes seen as a good practice). The fact that we declare them privatemake them only accessible in their own class. If You however need to use them in a function in another class then you need to follow the first method you described
.
using a getter makes it read-only.
(that's the only conceptual difference. a language could easily allow interfaces to be defined in terms of properties as well as methods. naming conventions are not really fundamental.)
Related
I see quite often (ie within the Slim framework) that single function accessor style (like in [1] below) is deprecated in favor to classical Java-ish 2 functions accessors (get/set) (like in [2] below).
Personally I rather prefer less lines of code (in [1]) and less typing (get/set) than being able to chain setter calls like in [3] (which I consider awful).
Am I missing something?
class Test {
protected $body;
// [1] single function accessor
public function body($body = null)
{
if (!is_null($body))
$this->body=$body;
return $this->body;
}
// [2] dual function accessors
public function getBody()
{
return $this->body;
}
// [2] dual function accessors
public function setBody($body)
{
$this->body=$body;
//[3] ok, you could return $this for chaining
}
}
Are Single Function Accessors A Bad Habit?
They are not a good idea. The reasons are simple:
They have multiple responsibilities (setting and getting data). Good functions have a single responsibility and do it well.
They mask intent. You can't look at the method call and understand what's going to happen.
What do you think the body() method does? Well, body is a noun. And having a method (which should be a verb) being a noun is confusing.
But what if the method was age(). Age is both a verb and a noun. So when you see $obj->age(), are you telling the object to give you its age? Or are you telling the object to age itself?
Whereas $obj->getAge() is crystal clear what you're trying to do. And $obj->getBody() is equally clear.
It adds complexity to methods.
Your overall complexity will stay the same (because the same logic exists), but it shifts to fewer methods. Which means that instead of having 2 dead simple methods, you have one more complicated method.
So yeah, I'd avoid it.
But let's step back a minute. Rather than asking the question if "Single Function Accessors" are a bad habit, let's ask the same question about accessors in general...
Are Property Accessors A Bad Habit?
My answer is: yes.
Depends on Role of Object:
What it depends on is the role of the object, and the role of the specific property. It's a case-by-case basis.
There are tons of different types of objects (domain objects, services, proxies, collections, etc). Some are stateful, and some are not.
If the object isn't stateful, it has no properties and hence we can ignore it.
For those objects that have state, why do they have that state?
If it's because they represent the state, then the state should be public (not saying the property should be public, but the state should be exposed to the outside world). So domain models which represent business entities should have public state.
class User {
public $name;
}
But if the role of the object isn't to represent the state, but to do something with it, then it shouldn't be exposed.
class UserMapper {
protected $pdo;
public function __construct(Pdo $connection) {
$this->pdo = $connection;
}
public function findUserById($id) {
...
}
In the mapper case, $pdo is incidental state. The mapper's job isn't to represent the data of the database connection, but it needs it to work.
The Bottom Line
The bottom line is never expose state that the object isn't directly representing.
Just because you have a property, doesn't mean you should expose it. In fact, often times you shouldn't expose it. This is known as Information Hiding.
Depends On Type Of State:
But what about types of objects that are stateful? Well, as it turns out there are two fundamental types of state:
Application State
Think Configuration and things like that. Basically state that's not defined at build time, but is known at runtime.
It's important to note that this state shouldn't change through the course of a request. And it also should be reasonably the same request-to-request (aside from deploys, etc).
User State
Think state and data that's derived or dependent upon user input. An obvious example would be data that was submitted from a form.
But a less obvious example would be if you use different renderers for different types of representations. So if a user requested a JSON response, the JSON rendering code being set in a property would be considered user state.
My assertion:
Property accessors for application state are bad. There's no reason that application state should change mid-run, therefore there's no reason that you should have to propagate the state.
Property accessors for user state may be OK. But there's more to it than that.
Depends On What The Accessor Does
In the case of your example:
public function setBody($body)
{
$this->body=$body;
}
You're essentially making $body a public property.
And there's nothing wrong with that. But why do you need a method? What's wrong with: public $body; in the first place?
Some people will say "properties are evil, they must never be public!". And that's hogwash, since that's exactly what you did with that accessor.
Now, if the accessor did some typing information (through type hints), or other validation logic (minimum length, etc), then that's a different story...
Or is it?
Let me give an example.
class Person {
public $name;
public $age;
}
vs
class StrictPerson {
protected $name;
protected $age;
public function setName($name) {
if (!is_string($name)) throw new BlahException();
if (strlen($name) < 10) throw new InvalidException();
$this->name = $name;
}
public function getName() {
return $this->name;
}
public function setAge($age) {
if (!is_int($age)) throw new ....
if ($age < 0 || $age > 150) throw new ...
$this->age = $age;
}
public function getAge() {
return $this->age;
}
}
Now, it should be clearly obvious that those properties are always valid. Right? Right? Right?
Well, no. What would happen if I created a child:
class LoosePerson extends StrictPerson {
public function setName($name) {
$this->name = $name;
}
public function setAge($age) {
$this->age = $age;
}
}
All of a sudden, all of our validation disappears. Now you could argue that was intended and it's the programmer's problem. Or you could simply change the properties to be private instead, to hold them always being valid. Right? Right? Right?
Well, no. What would happen if I did this:
$a = new StrictPerson;
$r = new ReflectionProperty($a, 'name');
$r->setAccessible(true);
$r->setValue($a, 'Bob');
I've just set an invalid value onto an object that's supposed to always validate.
The Bottom Line
Using accessors as validators only works if you always use them. And every tool that you use always uses them. Things like mysqli and PDO and Doctrine and PHPUnit which set the property directly rather than calling setters can cause massive problems.
Instead, you can use an external validator:
class PersonValidator {
public function validate(Person $person) {
if (!is_string($person->name)) {
throw new Blah...
}
if (strlen($person->name) < 10) {
throw new Blah...
}
if (!is_int($age)) throw new ....
if ($age < 0 || $age > 150) throw new ...
return true;
}
}
So, Are Property Accessors A Bad Habit?
I argue that yes, often times they are a bad habit.
Now, there are some cases where you should use them:
When you must represent that state in an interface
Properties are not specifiable in an interface. So if you must represent that the object exposes state in an interface, then you should use a getter and a setter.
I'd strongly urge you to consider why you are creating the interface. For simple data objects, it's often better to rely on the core object type (since polymorphism can't benefit due to there being no logic on the data object).
When you need to hide the internal representation for some reason.
An example would be a class that represents a unicode string. You may have an accessor method to get the raw value. But you'd want that to be a method so that you could convert the internal representation to a string of the proper character set.
That brings up an interesting point.
When you create an accessor, you should never create a property accessor. You should instead create a state accessor. The difference is that property accessors must always return a property or set it).
A state accessor on the other hand can "fake it" if it needs to. So our example above about the unicode string class, could internally represent the string as an array of code points. Then when you access the "string" state, it will convert the array into an actual string.
Objects Should Abstract
If you're going to use an accessor, it should be to abstract state. Not to represent it.
The Bottom Line / TLDR
Property accessors are a bad habit. If you're going to do that, make the properties public and use a validator object.
State accessors are not a bad habit. They are quite useful for maintaining useful abstractions.
Pass all your objects dependencies in the constructor and just have getters to access them, no need for setters most of the time.
Further to #Kleskowy and #marty answers, the best possible solution for doing this is like the following:
class Test {
protected $body;
public function body()
{
$args=func_get_args();
if (count($args)==1) //simple setter
$this->body=$args[0];
elseif (count($args)) //setter for an array
$this->body=$args;
else //getter
return $this->body;
}
}
The #marty's idea ends up in a nice way to create an array which is equivalent to PHP 5.4 [] syntax (except assoc arrays). But still compatible with PHP 5 to 5.3 ;-)
You can then write:
$a->body("a"); //a value
$a->body(null); //set to null is possible
$a->body("this","is","an","array"); //convenient way to initialize $body as an array
$a->body(); //get the value
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
Okay, this is really bugging me and I'm starting to think it all comes down to personal choice rather than a particular way of being more efficient or writing better code: Should I or should I not use getter/setter methods within a PHP project? The answers so far that I've read are rather conflicting and not entirely suited towards PHP, which is not a compiled language. For example, take this question on Stack Overflow ("Why use getters and setters?"). There's a number of good reasons presented as to why I should use them within my code, yet all the child comments mention how Accessors are evil and should be avoided, interspersed between a few more disturbing comments which mention that they should be avoided entirely because it "mucks up your code".
All I'm getting is conflicting answers, none of which are relevant to a interpreted PHP environment. Can someone shine some light on why/why not they should be used within PHP, and their rationale behind that decision? Does it really matter if we can simply define a property as private or protected and, anyway:
The encapsulation getters and setters offer are laughably thin
... quoted from "sbi" (Why use getters and setters?)
Personally, I still don't see how:
Class Foo {
public $bar;
function setBarType($val) {
$this->bar = $val;
}
}
$fee = new Foo();
$fee->setBarType(42);
is superior to this:
Class Foo {
public $bar;
}
$fee = new Foo();
$fee->bar = 42;
The blog post you linked to starts with a crucial sentence (emphasis added) :
Every getter and setter in your code represents a failure to encapsulate and creates unnecessary coupling.
Encapsulation is the most important idea of Object Oriented Programming. It essentially boils down to hiding complexity by wrapping it neatly inside classes. In an ideal world, when you use a class, you shouldn't have to know anything whatsoever about its inner workings or its state. Some people (like this blog author) will argue that having getters and setters is already way too much information about the insides of the class. In their view, a class should only have methods that enable us to tell an object to do something, never mind how it does it or what state it is in. Using a setter is not "telling the object to do something", it is mucking with the object's state from outside.
Instead of doing this :
$a = myObject();
// Querying object state, making a decision outside the object, and changing its state
if ($a->getWarbleFizz() < 42) {
$a->setYourWarbleFizzTo(42);
}
// Gee, I hope I made the right decision...
$a->nowDoSomethingUseful();
You should be writing code like this :
$a = myObject(42);
$a->doStuff();
Or this :
$a = myObject();
$a->doStuff(42);
Related reading : Tell, don't ask.
Because if the implementation of how the value is set changes (to a db), you don't have to change the callers. Another example is that you may need to do some checking on the value before setting it.
Having a method lets you intercept the setting/getting of that variable, doing it when it doesn't seem like you need it makes your code more change friendly.
Property getters
Languages like C# and recent versions of JavaScript allow you to intercept property reading and writing, so you can just use properties in languages that support it.
Object watchers
Some languages allow you to intercept the reading/setting of all JavaScript's Object.watch, or inaccessible properties with PHP's __get. This allows you to implements getters and setters but you get a performance hit because of the overhead they create for every property access. This answer talks about other problems with getters and setters. Best practice: PHP Magic Methods __set and __get
Getters and Setters are OK, but...
Just making boilerplate getters and setters is better, but is almost as bad as public properties. If anybody can change your object's state (specially with multiple properties), it won't be well encapsulated. http://cspray.github.io/2012/05/13/stop-calling-them-getters-setters.html
A great profit of using a getter and setter is, whenever you need to make changes you only have to modify the getter and setter.
I'll try to explain with an example:
protected $date;
public function getDate(){
return $this->date;
}
public function setDate($date){
$this->date = $date;
}
Imagine there is a reason the date should always be incremented with one day. You will have to search in your entire project where you accessed your class member.
But by using getters and setters you could change the code to:
protected $date;
public function getDate(){
return $this->date;
}
public function setDate($date){
$date = new DateTime($date);
$date->modify('+1 day');
$this->date = $date;
}
One OOP principe is encapsulation. A class is responsible to all variables that are contained inside this class.
By setting a public variable, you are breaking that principe.
By creating an accessor (setter), you're indirectly breaking that principe by giving a chance for that value to be changed outside of the class.
The advantage of a getter is that the calling method don't need to care about how the data is retrieved. It only know that it will get the expected data and that's all. Here the encapsulation principe is respected.
The advantage of a setter is that the class have the chance to check the new value before applying it. In a perfect world, there is no need for accessors because a class can fully manage all his variables. In the real world, sometimes you need to set a value or get it from the outside.
The best way to approach the perfect world is to limit accesors only to the very few variables that have to be modified. And check setted values if possible.
About your example, the second solution is better because you save one level in the php stack. Your accessor is useless because you variable is public anyway (so, no encapsulation) and don't perform any additionnal check. But when possible, you SHOULD use accessor to check the data. If the data isn't needed anywhere else in your application, then, don't do any accessor.
If you don't use getters and setters in a language like PHP, which is not type safe, then how are you going to ensure the type of the object's property is correct?
I may be missing the point completely, but if you need access to a property from outside of the object, I think it's still the best option to use accessors...
Also, as Juon Mendes mentions: some languages offer you to intercept when the properties themselves are being addressed. This may also be coming to PHP
You could even have a public setter, and a protected getter:
class TimePeriod {
protected $Seconds = 3600;
public $Hours {
get { return $this->Seconds / 3600; }
set { $this->Seconds = $value * 3600; }
}
// This property is read only as there is no setter
public $Minutes {
get { return $this->Seconds / 60; }
}
/* public getter, protected setter */
public $Milliseconds {
get { return $this->Seconds * 1000; }
protected set { $this->Seconds = $value / 1000; }
}
}
The choice is up to you. Other important features of PHP 5 to consider are magic getter/setters:
http://www.php.net/manual/en/language.oop5.overloading.php#object.set
http://www.php.net/manual/en/language.oop5.overloading.php#object.get
The magic of this is that you are able to do something like the following and decide where to get/set variables without having to declare them beforehand:
Class Foo {
private $data = array();
function __set($name,$val) {
$this->$data[$name] = $val;
}
function __get($name) {
if (array_key_exists($name, $this->data)) {
return $this->data[$name];
}
else {
return null;
}
}
Voila, something like this now happens automagically:
$fee = new Foo();
$fee->bar = 42;
IMO using getters and setters is a good practice and increases code readability too.
Apart from checking the value while setting, there is another example, consider if u call getMoviesList(). Now this get method can be implemented in anyway, it can get movies list from the local db, get it from the online web service and so on... So the code making the decision maybe inside this function. Wherever u call it from, u don't care about the location and how it gets it. U just get the movies list.
Say I have a class which represents a person, a variable within that class would be $name.
Previously, In my scripts I would create an instance of the object then set the name by just using:
$object->name = "x";
However, I was told this was not best practice? That I should have a function set_name() or something similar like this:
function set_name($name)
{
$this->name=$name;
}
Is this correct?
If in this example I want to insert a new "person" record into the db, how do I pass all the information about the person ie $name, $age, $address, $phone etc to the class in order to insert it, should I do:
function set($data)
{
$this->name= $data['name'];
$this->age = $data['age'];
etc
etc
}
Then send it an array? Would this be best practice? or could someone please recommend best practice?
You should have setter/getter methods. They are a pain but you don't necessarily have to write them yourself. An IDE (for example Eclipse or Netbeans) can generate these for you automatically as long as you provide the class member. If, however, you don't want to deal with this at all and you're on PHP5 you can use its magic methods to address the issue:
protected $_data=array();
public function __call($method, $args) {
switch (substr($method, 0, 3)) {
case 'get' :
$key = strtolower(substr($method,3));
$data = $this->_data[$key];
return $data;
break;
case 'set' :
$key = strtolower(substr($method,3));
$this->_data[$key] = isset($args[0]) ? $args[0] : null;
return $this;
break;
default :
die("Fatal error: Call to undefined function " . $method);
}
}
This code will run every time you use a nonexistent method starting with set or get. So you can now set/get (and implicitly declare) variables like so:
$object->setName('Bob');
$object->setHairColor('green');
echo $object->getName(); //Outputs Bob
echo $object->getHairColor(); //Outputs Green
No need to declare members or setter/getter functions. If in the future you need to add functionality to a set/get method you simply declare it, essentially overriding the magic method.
Also since the setter method returns $this you can chain them like so:
$object->setName('Bob')
->setHairColor('green')
->setAddress('someplace');
which makes for code that is both easy to write and read.
The only downside to this approach is that it makes your class structure more difficult to discern. Since you're essentially declaring members and methods on run time, you have to dump the object during execution to see what it contains, rather than reading the class.
If your class needs to declare a clearly defined interface (because it's a library and/or you want phpdoc to generate the API documentation) I'd strongly advise declaring public facing set/get methods along with the above code.
Using explicit getters and setters for properties on the object (like the example you gave for set_name) instead of directly accessing them gives you (among others) the following advantages:
You can change the 'internal' implementation without having to modify any external calls. This way 'outside' code does not need change so often (because you provide a consistent means of access).
You provide very explicitly which properties are meant to be used / called from outside the class. This will prove very useful if other people start using your class.
The above reasons is why this could be considered best practice although it's not really necessary to do so (and could be considered overkill for some uses ; for example when your object is doing very little 'processing' but merely acts as a placeholder for 'data').
I perfectly agree with CristopheD (voted up). I'd just add a good practice when creating a new person.
Usually, a use a constructor which accept the mandatory fields and set the default values for the optional fields. Something like:
class Person
{
private $name;
private $surname;
private $sex;
// Male is the default sex, in this case
function Person($name, $surname, $sex='m'){
$this->name = $name;
$this->surname = $surname;
$this->sex = $sex;
}
// Getter for name
function getName()
{
return $this->name;
}
// Might be needed after a trip to Casablanca
function setSex($sex)
{
$this->sex = $sex;
}
}
Obviously, you could use the setter method in the constructor (note the duplicate code for the sex setter).
To go full OOP, you should do something similar to:
class User {
private $_username;
private $_email;
public function getUsername() {
return $this->_username;
}
public function setUsername($p) {
$this->_username = $p;
}
...
public function __construct() {
$this->setId(-1);
$this->setUsername("guest");
$this->setEmail("");
}
public function saveOrUpdate() {
System::getInstance()->saveOrUpdate($this);
}
}
If you want to save a user, you just create one, assign its values using Setters and do $user->saveOrUpdate(), and have another class to handle all the saving logic.
As a counterpoint to ChristopheD's answer, if your instance variable is strictly for private use, I wouldn't bother with writing a getter & setter, and just declare the instance variable private.
If other objects need to access the object, you can always add a getter. (This exposes another problem, in that other classes might be able to change the object returned by the getter. But your getter could always return a copy of the instance variable.)
In addition using a getter/setter also shields other parts of the same class from knowing about its own implementation, which I've found very useful on occasion!
From a more general point of view both direct access ($person->name) and accessor methods ($person->getName) are considered harmful. In OOP, objects should not share any knowledge about their internal structure, and only execute messages sent to them. Example:
// BAD
function drawPerson($person) {
echo $person->name; // or ->getName(), doesn't matter
}
$me = getPersonFromDB();
drawPerson($me);
// BETTER
class Person ....
function draw() {
echo $this->name;
}
$me = getPersonFromDB();
$me->draw();
more reading: http://www.javaworld.com/javaworld/jw-09-2003/jw-0905-toolbox.html
Or in more specific words, is it "ok" to not be relying on setters and getters?
I'm dealing with a class that checks the availability of rooms and sets public properties of which there are more than a dozen. Things such as:
unitNumber
roomTypes ( array )
codeCorporate
codeGroup
numberKids
numberAdults
numberRooms
currency
minRate
maxRate
soapServer
units ( array )
hotelId
And after an object is instantiated those properties are set with $this-> inside various methods. However the code that deals with the object often sets public properties directly instead of using getter/setter methods:
$object->something = 3;
foreach ($object->things as $thing ) { }
If I have the time to refactor this class..
Should I stick all of these properties in a data array that's a private property, and define __set and __get methods?
Should I make a single getter method for each of the properties?
In my opinion, it is rarely a good idea to have any public members. It increases coupling between classes, and makes refactoring very complicated (should you need it.)
Setters/Getters are the way to go, and the very small performance penalty that you pay for it is usually either optimized away, or trumped by elegance.
To answer your question about array vs. single-getter-per-var, it's a matter of taste. I tend to only keep variables of a similar type within an array, and separate the rest.
I personally have yet to find a truly good reason for a public property, though im open for suggestion :-)
Although i much prefer specified getters/setters for each property (whether that's a proxy to a generalized get($name) or not). I assume you have other code already that uses direct assignment so in that case i would say to proceed with using the magic __get/__set methods.
I think most people will recommend using setters & getters. Right now you're limited to simply setting & fetching the property, but what if you want to log when that property is accessed? Or perhaps you want to run the value by a validation function first (email, phonenumber, zip code, etc). Maybe you'll need to call another function, or set another property. I think you see where I'm heading with this. By using setters & getters, you add a valuable layer of encapsulation to your classes, and 99% of the time this is worth the extra typing you'll need to do ;) Imagine trying to do the examples above without setters & getters. It'd be a big headache to say the least.
Edit: I forgot to mention Doctrine. It's an object relation mapper (ORM) that can automatically setup setters & getters for you (amongst other things). You can check it out at http://www.doctrine-project.org/
I would take a step back and ask some more general questions:
Why am I having to expose this much information; what is using it and why?
Is this class really just a data structure without behavior, in which case should be a private class to some other class?
Does this class serve a single purpose, or is it on the path to becoming monolithic?
You may discover that you are able to create views of an instance of a class to export to a database, display in a form, etc. Check out the "Builder" and "Acyclic Visitor" patterns to start with.
Regarding accessors, I do not see a need to use them for what you are describing: retrieving class properties and internal state information, aka a struct. However, for attributes of a class I could see the benefit in certain cases, but more for retrieving attributes, not for mutations of your object's state.
If I may add my grain of salt several months later :
It is very un-OO to have public properties. Everything should be encapsulated, simply because (among other reasons) using direct attribute manipulation doesn't give you ways to easily refactor or perform (more) control checks when some external source modifies the field. For example, let's say you have a class with many fields that is used throughout a project several times, and that project contains several thousands of files; it's a project that has been running and expanded for a few years now. Let's say that the company is changing it's business model, or that a problem is found with some of the field's data type and now is required to have some validation; will you duplicate that validation in all those thousands of source code that is directly accessing the public member? In PHP, the solution may be simple, but not in most OO programming language (i.g. Java). The fact is that OO is based on encapsulation. In short, encapsulation doesn't only produce clean code, but also highly maintainable (not to say cost-effective and cohesive) code.
Your suggestion of having a private member (array) being manipulated by __get / __set is good. This way, if you need some extra validation along the road, simply create your setter and/or your getter and it will be the end of it. Some may argue with that being counter productive as the code completion cannot kick-in on __get / __set. IMHO, relying on code completion is simply lazy coding. But then again, having every member have it's own getter and/or setter allows you to write a more comprehensive API documentation. Personally, I usually use that technique for internal or very general purpose classes. If all your fields do not require any validation, or there are as you said several dozen of them, then using magic methods would be acceptable, in my opinion.
The bottom line is to avoid direct member access on class instances, period. How you decide to achieve this is strictly up to you. Just make sure that the API is well documented the more abstract you make it.
On a final note, in PHP, if you already have classes that are being used that are not encapsulating their fields, for example something like
class SomeObject {
public $foo;
public $bar;
public $baz;
//...
}
you can simply fix this class without having to refactor anything with something like :
class SomeObject {
private $_foo; // having underscore as prefix helps to know what's private/protected
private $_bar; // inside the code.
private $_baz;
public function __get($name) {
$methodName = 'get'.ucfirst($name);
if (method_exists($this, $methodName)) {
return $this->{$methodName}();
} else {
throw new Exception("Method '{$methodName}' does not exist");
}
}
public function __set($name, $value) {
$methodName = 'set'.ucfirst($name);
if (method_exists($this, $methodName)) {
$this->{$methodName}($value);
} else {
throw new Exception("Method '{$methodName}' does not exist");
}
}
public function getFoo() { return $this->_foo; }
public function setFoo($value) { $this->_foo = $value; }
public function getBar() { return $this->_bar; }
public function setBar($value) { $this->_bar = $value; }
public function getBaz() { return $this->_baz; }
public function setBaz($value) { $this->_baz = $value; }
}
And then
$obj = new SomeObject();
$obj->foo = 'Hello world'; // legacy code support
$obj->setFoo('Hello world'); // same thing, but preferred
And you satisfy both the OO paradigm and having direct access to attributes of an instance. You could also have __call() check for prefix 'get' or 'set' and call __get() and __set() accordingly, but I would not go that far, though this would truly enable general purpose classes to access it's private members via ->member and ->getMember()/->setMember()
(This question uses PHP as context but isn't restricted to PHP only. e.g. Any language with built in hash is also relevant)
Let's look at this example (PHP):
function makeAFredUsingAssoc()
{
return array(
'id'=>1337,
'height'=>137,
'name'=>"Green Fred");
}
Versus:
class Fred
{
public $id;
public $height;
public $name;
public function __construct($id, $height, $name)
{
$this->id = $id;
$this->height = $height;
$this->name = $name;
}
}
function makeAFredUsingValueObject()
{
return new Fred(1337, 137, "Green Fred");
}
Method #1 is of course terser, however it may easily lead to error such as
$myFred = makeAFredUsingAssoc();
return $myFred['naem']; // notice teh typo here
Of course, one might argue that $myFred->naem will equally lead to error, which is true. However having a formal class just feels more rigid to me, but I can't really justify it.
What would be the pros/cons to using each approach and when should people use which approach?
Under the surface, the two approaches are equivalent. However, you get most of the standard OO benefits when using a class: encapsulation, inheritance, etc.
Also, look at the following examples:
$arr['naem'] = 'John';
is perfectly valid and could be a difficult bug to find.
On the other hand,
$class->setNaem('John');
will never work.
A simple class like this one:
class PersonalData {
protected $firstname;
protected $lastname;
// Getters/setters here
}
Has few advantages over an array.
There is no possibility to make some typos. $data['firtsname'] = 'Chris'; will work while $data->setFirtsname('Chris'); will throw en error.
Type hinting: PHP arrays can contain everything (including nothing) while well defined class contains only specified data.
public function doSth(array $personalData) {
$this->doSthElse($personalData['firstname']); // What if "firstname" index doesn't exist?
}
public function doSth(PersonalData $personalData) {
// I am guaranteed that following method exists.
// In worst case it will return NULL or some default value
$this->doSthElse($personalData->getFirstname());
}
We can add some extra code before set/get operations, like validation or logging:
public function setFirstname($firstname) {
if (/* doesn't match "firstname" regular expression */) {
throw new InvalidArgumentException('blah blah blah');
}
if (/* in debbug mode */) {
log('Firstname set to: ' . $firstname);
}
$this->firstname = $firstname;
}
We can use all the benefits of OOP like inheritance, polymorphism, type hinting, encapsulation and so on...
As mentioned before all of our "structs" can inherit from some base class that provides implementation for Countable, Serializable or Iterator interfaces, so our structs could use foreach loops etc.
IDE support.
The only disadvantage seems to be speed. Creation of an array and operating on it is faster. However we all know that in many cases CPU time is much cheaper than programmer time. ;)
After thinking about it for some time, here's my own answer.
The main thing about preferring value objects over arrays is clarity.
Consider this function:
// Yes, you can specify parameter types in PHP
function MagicFunction(Fred $fred)
{
// ...
}
versus
function MagicFunction(array $fred)
{
}
The intent is clearer. The function author can enforce his requirement.
More importantly, as the user, I can easily look up what constitutes a valid Fred. I just need to open Fred.php and discover its internals.
There is a contract between the caller and the callee. Using value objects, this contract can be written as syntax-checked code:
class Fred
{
public $name;
// ...
}
If I used an array, I can only hope my user would read the comments or the documentation:
// IMPORTANT! You need to specify 'name' and 'age'
function MagicFunction(array $fred)
{
}
Depending on the UseCase I might use either or. The advantage of the class is that I can use it like a Type and use Type Hints on methods or any introspection methods. If I just want to pass around some random dataset from a query or something, I'd likely use the array. So I guess as long as Fred has special meaning in my model, I'd use a class.
On a sidenote:
ValueObjects are supposed to be immutable. At least if you are refering to Eric Evan's definition in Domain Driven Design. In Fowler's PoEA, ValueObjects do not necessarily have to be immutable (though it is suggested), but they should not have identity, which is clearly the case with Fred.
Let me pose this question to you:
What's so different about making a typo like $myFred['naem'] and making a typo like $myFred->naem? The same issue still exists in both cases and they both error.
I like to use KISS (keep it simple, stupid) when I program.
If you are simply returning a subset of a query from a method, simply return an array.
If you are storing the data as a public/private/static/protected variable in one of your classes, it would be best to store it as a stdClass.
If you are going to later pass this to another class method, you might prefer the strict typing of the Fred class, i.e. public function acceptsClass(Fred $fredObj)
You could have just as easily created a standard class as opposed to an array if it is to be used as a return value. In this case you could care less about strict typing.
$class = new stdClass();
$class->param = 'value';
$class->param2 = 'value2';
return $class;
A pro for the hash: It is able to handle name-value combinations which are unknown at design time.
When the return value represents an entity in your application, you should use an object, as this is the purpose of OOP. If you just want to return a group of unrelated values then it's not so clear cut. If it's part of a public API, though, then a declared class is still the best way to go.
Honestly, I like them both.
Hash arrays are way faster than making objects, and time is money!
But, JSON doesn't like hash arrays (which seems a bit like OOP OCD).
Maybe for projects with multiple people, a well-defined class would be better.
Hash arrays might take more CPU time and memory (an object has a predefined amount), though its hard to be sure for every scenario.
But what really sucks is thinking about which one to use too much. Like I said, JSON doesn't like hashes. Oops, I used an array. I got to change a few thousand lines of code now.
I don't like it, but it seems that classes are the safer way to go.
The benefit of a proper Value Object is that there's no way to actually make an invalid one and no way to change one that exists (integrity and "immutability"). With only getters and type hinting parameters, there's NO WAY to screw it up in compilable code, which you can obviously easily do with malleable arrays.
Alternatively you could validate in a public constructor and throw an exception, but this provides a gentler factory method.
class Color
{
public static function create($name, $rgb) {
// validate both
if ($bothValid) {
return new self($name, $rgb);
} else {
return false;
}
}
public function getName() { return $this->_name; }
public function getRgb() { return $this->_rgb; }
protected function __construct($name, $rgb)
{
$this->_name = $name;
$this->_rgb = $rgb;
}
protected $_name;
protected $_rgb;
}
I have worked with OOP Languages over 10 years.
If you understand the way objects work you will love it.
Inheritance, Polymorphism, Encapsulation, Overloading are the key advantage of OOP.
On the other hand when we talk about PHP we have to consider that PHP isn't a full featured Object Oriented language.
For example we cant use method overloading or constructor overloading (straightforward).
Associative arrays in PHP is a VERY nice feature but i think that harms php enterprise applications.
When you write code you want to get clean and maintainable application.
Another think that you loose with Associative arrays is that you can't use intellisense.
So i think if you want to write cleanner and more maintainable code you have to use the OOP features when it is provided.
I prefer to have hard-coded properties like in your second example. I feel like it more clearly defines the expected class structure (and all possible properties on the class). As opposed to the first example which boils down to just always remembering to use the same key names. With the second you can always go back and look at the class to get an idea of the properties just by looking at the top of the file.
You'll better know you're doing something wrong with the second one -- if you try to echo $this->doesntExist you'll get an error whereas if you try to echo array['doesntExist'] you won't.