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
Related
I am reading an article about constructors doing too much work.
One paragraph reads
In the object oriented style, where dependencies tend to be inverted, the constructor has a different and more Spartan role. Its only job is to make sure that object initializes into a state where it satisfies its basic invariants (in other words, it makes sure that the object instance starts off in a valid state and nothing more).
Here is a basic example of a class. On creation of the class I pass in the HTML which needs parsed to then set the class properties.
OrderHtmlParser
{
protected $html;
protected $orderNumber;
public function __construct($html)
{
$this->html = $html;
}
public function parse()
{
$complexLogicResult = $this->doComplexLogic($this->html);
$this->orderNumber = $complexLogicResult;
}
public function getOrderNumber()
{
return $this->orderNumber;
}
protected function doComplexLogic($html)
{
// ...
return $complexLogicResult;
}
}
I'm calling it using
$orderparser = new OrderHtmlParser($html);
$orderparser->parse()
$orderparser->getOrderNumber();
I use a parse function because I dont want the constructor to be doing any logic as both the article above and this article state this is terrible practice.
public function __construct($html)
{
$this->html = $html;
$this->parse(); // bad
}
However if I don't use the parse method, then all my properties (in this example just the one) would return null.
Is this known as an object in an 'invalid state'?
Also, it somewhat feels like my parse method is an initialise function in disguise, which is also deemed bad by the other article (although im not sure if that is only when a constructor calls that method, when it is manually called or both). Regardless, the initialise method is still doing some complex logic prior to setting a property - which needs to happen before the getters can be reliably called.
So either I am misunderstanding these articles or these articles are pushing me to think that maybe my overall implementation of this simple class is incorrect.
Generally, it's a code smell to perform work in a constructor, but the reason behind the practice has more to do with the programming language than an opinion about best practices. There are real edge cases that will introduce bugs.
In some languages derived classes have their constructors executed from the bottom up, and in other languages from the top down. In PHP they are called from top to bottom and you can even stop the chain by not calling parent::__construct().
This creates unknown state expectations in base classes, and to make matters worse PHP allows you to either call parent first or last in a constructor.
For Example;
class A extends B {
public __construct() {
$this->foo = "I am changing the state here";
parent::__construct(); // call parent last
}
}
class A extends B {
public __construct() {
parent::__construct(); // call parent first
$this->foo = "I am changing the state here";
}
}
In the above example class B has it's constructor called in different orders and if B was doing a lot of work in the constructor, then it might not be in the state the programmer was expecting.
So how do you solve your problem?
You need two classes here. One will contain the parser logic and the other the parser results.
class OrderHtmlResult {
private $number;
public __construct($number) {
$this->number = $number;
}
public getOrderNumber() {
return $this->number;
}
}
class OrderHtmlParser {
public parse($html) {
$complexLogicResult = $this->doComplexLogic($this->html);
return new OrderHtmlResult($complexLogicResult);
}
}
$orderparser = new OrderHtmlParser($html);
$order = $orderparser->parse($html)
echo $order->getOrderNumber();
In the above example you could have the parse() method return null if it fails to extract the order number, or throw an example. But neither class ever enters into an invalid state.
There is a name for this pattern, where a method yields another object as the result in order to encapsulate state information, but I remember what it's called.
Is this known as an object in an 'invalid state'?
Yes. You're exactly correct that the parse method is an initialise function in disguise.
To avoid the initialization parsing, be lazy. The laziest approach is to eliminate the $orderNumber field and parse it from the $html inside of the getOrderNumber() function. If you expect that function to be called repeatedly and/or you expect the parsing to be expensive, then keep the $orderNumber field but treat is as a cache. Check it for null inside of getOrderNumber() and parse it out only on the first invocation.
Regarding the linked articles, I agree in principle that constructors should be limited to field initialization; however, if those fields are parsed from a block of text and the expectation is that clients will utilize most or all of the parsed values, then lazy initialization has little value.
Furthermore, when the text parsing does not involve IO or newing up domain objects, it should not impede blackbox testing, for which eager vs. lazy initialization is invisible.
One of the common problems that occurs when the constructor does "too much" is that two objects that are somewhat closely linked need to reference each other (Yes, the close linking is a bad smell, but it happens).
If Object A and Object B must reference each other in order to be "Valid", then how do you create either?
The answer is usually that your constructor makes objects that are not fully "Valid", you add the reference to the other invalid object and then you call some kind of finalize/initialize/start method to finish and make your object valid.
If you still want to be "Safe", you can protect your business methods by throwing a not initialized exception if it's called before the object is "Valid".
Dependency Injection has a generalized version of this problem, what if you had a circular loop of injected classes? Following the construct/initialize pattern solves the general case too, so DI just always uses that pattern.
Addressing the question in the title I have always viewed an object as being in a valid state when it can perform its work without any issues; that is to say, it works as expected.
In looking at the linked article what jumped out at me was that the constructor logic was creating a lot of objects: I counted 7. All of these objects were tightly coupled with the class in question (ActiveProduct) as they were referenced directly and the constructor was passing the this pointer to the other objects constructors:
VirtualCalculator = new ProgramCalculator(this, true);
DFS = new DFSCalibration(this);
In this case ActiveProduct has not yet completed its initialization yet ProgramCalculator and DFSCalibration can call back into ActiveProduct via methods and properties and cause all sorts of mischief so for this reason the code is highly suspect.
In general in OOP you want to be passing objects to the constructor not instantiating them in the constructor. Also you want to employ the Dependency Inversion Principle and use interfaces or abstract / pure virtual classes when passing objects to constructors which would allow for dependency injection.
In the case of your class OrderHtmlParser this doesn't seem to be an issue as the complex logic at issue doesn't appear to go outside of the OrderHtmlParser class. I was curious as to why the doComplexLogic function was defined as protected, implying that inheriting classes can call it.
That said how to deal with initialization may be as simple as making the Parse method static and using it to construct the instance of the OrderHtmlParser class and make the constructor private so that the caller has to call the Parse method to get an instance:
OrderHtmlParser
{
protected $html;
protected $orderNumber;
private function __construct()
{
}
public static function parse($html)
{
$instance = new OrderHtmlParser();
$instance->html = $html;
$complexLogicResult = $instance->doComplexLogic($this->html);
$instance->orderNumber = $complexLogicResult;
return $instance;
}
public function getOrderNumber()
{
return $this->orderNumber;
}
protected function doComplexLogic($html)
{
// ...
return $complexLogicResult;
}
}
I fully agree with the comment from #trincot:
When you create the Parser with the Constructor, there is no need to pass the html.
Maybe you want to use the Parser Object a second Time with another Input.
So to have a clean constructor, I use a reset() Function, which is also called in the Beginning and which resets the initial State of the Object.
Example:
class OrderHtmlParser
{
protected $html;
protected $orderNumber;
public function __construct()
{
$this->reset();
}
public function reset()
{
$this->html = null;
$this->orderNumber = null;
}
/**
* Parse the given Context and return the result
*/
public function parse($html)
{
// Store the Input for whatever
$this->html = $html;
// Parse
$complexLogicResult = $this->doComplexLogic($this->html);
// Store the Result for whatever
$this->orderNumber = $complexLogicResult;
// return the Result
return $this->orderNumber;
}
public function getOrderNumber(){}
protected function doComplexLogic($html){}
}
Like this, the Parsing Object can do, what it is supposed to do:
Parse as often as you want:
$parser = new OrderHtmlParser();
$result1 = $parser->parse($html1);
$parser->reset();
$result2 = $parser->parse($html2);
Thank you for the excellent question!
This is an error-prone design to pass extensive data to the constructor that will merely store it inside the object to process this large data later.
Let me quote your beautiful quote again (the bold mark is mine):
In the object oriented style, where dependencies tend to be inverted, the constructor has a different and more Spartan role. Its only job is to make sure that object initializes into a state where it satisfies its basic invariants (in other words, it makes sure that the object instance starts off in a valid state and nothing more).
The design of the parser class in your example is troublesome because the constructor takes the input data, which is real data to process, not just “initialization data” as mentioned in the quote below, but does not actually process the data.
According to professor Ira Pohl from the University of California, Santa Cruz, the main roles of constructors are: (1) initialize the object, (2) convert values when a class has different constructor each having a different list of arguments - this concept is known as constructor overloading, (3) check for correctness - when the constructor parameters are checked to belong to a legal range.
Anyway, even if constructors are meant to initialize, convert and check, it happens very quickly, without significant delays.
In the very old programming courses, in 1980-s, we were told that a program has input and output.
Think of the $html as of the program input.
The constructors are not supposed to accept the program input. They are only supposed to accept the configuration, initialization data like character set name or other configuration parameters that may not be provided later. If they accept large data, they will likely be needed to sometimes throw exceptions, and exceptions in a constructor is a very bad style. Exceptions in constructors should better be avoided to make the code easier to fathom. For example, you may pass a file name to the constructor, but you should not open files in the constructor, and so on.
Let me modify your class a little bit.
enum ParserState (undefined, ready, result_available, error);
OrderHtmlParser
{
protected $orderNumber;
protected $defaultEncoding;
protected ParserState $state;
public function __construct($orderNumber, $defaultEncoding default "utf-8")
{
$this->orderNumber = $orderNumber;
$this->defaultEncoding = $defaultEncoding;
$this->state = ParserState::ready;
}
public function feed_data($data)
{
if ($this->state != ParserState::ready) raise Exception("You can only feed the data to the parser when it is ready");
// accumulate the data and parse it until we get enough information to make the result available
if we have enough result, let $state = ParserState::resultAvailable;
}
public function ParserState getState()
{
return $this->state
}
public function getOrderNumber()
{
return $this->orderNumber;
}
protected function getResult($html)
{
if ($this->state != ParserState::resultAvailable) raise Exception("You should wait until the result is available");
// accumulate the data and parse it until we get enough information to make the result available
}
}
If you conceive the class to have an evident design, programmers who use your class will not forget to call any method. The design in your original question was flawed because, contrary to the logic, the constructor did take the data but didn’t do anything with it, and a particular function was needed that was not obvious. If you make the design simple and obvious, you will not need even states. The states are only needed for classes that accumulate data for a long time until the result is ready, like state machines, for example, asynchronous reading of the HTML from the TCP/IP socket to feed this data to a parser.
$orderparser = new OrderHtmlParser($orderNumber, "Windows-1251");
repeat
$data = getMoreDataFromSocket();
$orderparser->feed_data($data);
until $orderparser->getState()==ParserState::resultAvailable;
$orderparser->getResult();
As for your initial questions about object states: if you design a class in such a way that the constructor only gets initialization data while there are methods that receive and process the data, so there are no separate functions to store the data and parse the data that may be forgotten to call – no states are needed. If you still need states for long-living objects that collect or supply the data sequentially, you may use the enumeration type like in the example above. My example is in abstract language, not a particular programming language.
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.)
I've generally tried to stay away from PHP's magic methods because they seem to obfuscate an object's public interface. That said, they seem to be used more and more, at least, in the code I've read, so I have to ask: is there any consensus on when to use them? Are there any common patterns for using these three magic methods?
The main reason is that you do not need to type as much. You could use them for, say, an ORM record and act as implicit setters/getters:
using __call():
$user = new User();
$user->setName("Foo Bar");
$user->setAge(42);
$user->save();
using __set():
$user->name = "Foo Bar";
$user->age = 42;
which maps to a simple array:
array(
"name" => "Foo Bar",
"age" => 42
)
It is much easier to write such an array to the database than doing a lot of manual calls to collect all needed information. __set() and __get() have another advantage over public members: You are able to validate/format your data.
__call()
I've seen it used to implement behaviors, as in add extra functions to a class through a pluginable interface.
Pseudo-code like so:
$method = function($self) {};
$events->register('object.method', $method);
$entity->method(); // $method($this);
It also makes it easier to write mostly similar functions, such as in ORMs. e.g.:
$entity->setName('foo'); // set column name to 'foo'
__get()/__set()
I've mostly seen it used to wrap access to private variables.
ORMs are the best example that comes to mind:
$entity->name = 'foo'; // set column name to 'foo'
It allows you to do things like this:
class myclass {
private $propertybag;
public function __get($name) {
if(isset($this->propertybag[$name]) {return $this->propertybag[$name];}
throw new Exception("Unknown property " . (string) $name);
}
}
Then you can populate $propertybag from a SQL query in a single line, rather than setting a whole bunch of properties one by one.
Also, it allows you to have specific properties which are read-only (ie don't allow them to be modified via __set()). Maybe useful for an ID field, for example.
Also, you can put code into __get() and __set(), so you can do something more complex than just getting or setting a single variable. For example, if you have a storeID field, you may also want to provide a storeName property. You could implement that in __get() via a cross-reference lookup, so you may not need the name actually to be stored in the class. And of course storeName would not want to be implemented in __get().
Lots of possibilities there.
There are of course some down-sides of using magic methods. The biggest one for me is the fact that you lose the auto-complete functionality in your IDE. This may or may not matter to you.
Since magic methods can save you a LOT of coding when it comes to repetitive tasks like defining members, populating them and then retrieving them - instead of doing that boring, long piece of work, you can use mentioned 3 methods to shorten the time to code all that. If needed, I can provide a few examples tho they can be found in various tutorials over the net.
I don't know if it's general consensus, but the usual should apply - use where appropriate. If you find yourself to do repetitive task (define member, populate member, get member, call X functions that differ slightly) - magic methods might help you.
One common pattern is to have a single handle for your clients and proxy the calls to encapsulated objects or singletons based on naming conventions or configurations.
class db
{
static private $instance = null;
static public function getInstance()
{
if( self::$instance == NULL )
self::$instance = new db;
return self::$instance;
}
function fetch()
{
echo "I'm fetching\n";
}
}
class dataHandler
{
function __call($name, $argv)
{
if( substr($name, 0, 4) == 'data' )
{
$fn = substr($name, 4);
db::getInstance()->$fn($argv);
}
}
}
$dh = new dataHandler;
$dh->datafetch('foo', 'bar');
Same principles can be used to drive different backends of the same functionality without having to change the driver.
Whenever you'd like, as long as the magic properties/methods are documented; undocumented magic should be avoided unless working with a very abstract layer of code, such as when developing an ORM.
acceptable at an abstract layer
/**
* DB backed model base class.
*/
class Model {
protected $attributes = [];
function __get($name) {
return #$this->attributes[$name];
}
}
acceptable when documented
/**
* User model backed by DB tables.
* #property-read string $first_name
* #property-read string $last_name
*/
class UserModel extends Model {
}
lazy and unacceptable (and common when using ORMs)
/**
* This class is magical and awesome and I am a lazy shithead!
*/
class UserModel extends WhoCaresWhenEverythingIsMagical {
}
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.