PHP magic methods which are prefixed with a double underscore, e.g. _set(), pose a particular problem in mocking and unit testing in general.
It is strongly recommended that unit tests and mock objects do not directly refer to magic methods.
Instead, refer only to the virtual methods and properties these magic methods simulate.
Following this piece of advice will ensure you are testing the real API of classes and also ensures there is no conflict should Mockery override these magic methods, which it will inevitably do in order to support its role in intercepting method calls and properties.
This lead me to start re-evaluating my attitude to PHP’s magic methods.
Whereas previously I’ve loved using them for their simplicity and compactness, now I’m not so sure if the convenience is worth it.
As the manual suggests, "mock on the properties which the magic method refers to".
Fine, not a deal-breaker.
But perhaps it’s time to stop using them.
Maybe it’s time to write more getters and setters instead, in the name of fully testable code.
Maybe, while handy, they’re not worth using.
During research on the topic, I came across this Stack Overflow article, which in the comments, people make good arguments for and against.
Also, magic methods aren’t going to work with interfaces and abstract classes/methods.
And what about visibility?
It’s a leak to have a private or protected property modifiable by a magic __set method.
Add these to your examples and I agree that there are many good arguments against using magic methods for getter/setters<s></s>and no real arguments in their favor.
For quick one-offs, maybe use them for something, but they’re not a best practice for reusable code/libraries/APIs.
You should use stdClass if you want magic members, if you write a class - define what it contains.
Yes, this is exactly that :p.
But another thing I forgot to mention is that: having getters for properties is more coherent with "real" methods where getXXX is not only returning a private property but doing real logic.
You have the same naming.
For example you have $user→getName() (returns property) and $user→getToken()
First of all, back then it was very popular to use <acronym title="Pre-Hypertext Processing">PHP</acronym>’s magic functions (_\_get, \_\_call etc.). There is nothing wrong with them from a first look, but they are actually really dangerous. They make APIs unclear, auto-completion impossible and most importantly they are slow. The use case for them was to hack <acronym title="Pre-Hypertext Processing">PHP</acronym> to do things which it didn’t want to. And it worked. But made bad things happen.
Avoid writing naive setters and getters.
Instead, they suggest declaring class variables with public visibility.
Though, from my interpretation of the post, that’s only for the case of simple get and set, not where extra logic is required.
Join the discussion
comments powered by Disqus