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 {
}
Related
I understand that multiple inheritance1 is simply not supported in PHP, and while many "hacks" or workarounds exist to emulate it, I also understand that an approach such as object composition is likely more flexible, stable, and understandable than such workarounds. Curiously, PHP's 5.4's traits will be the fitting solution, but we're not quite there yet, are we.
Now, this isn't simply an "amidoinitrite?" question, but I'd like to ensure that my approach makes sense to others.
Given I have classes Action and Event (there are more, but we'll keep it brief) and they both require (near) identical methods, the obvious approach would be; create a common base class, extend and go; they are, after all, conceptually similar enough to constitute being siblings in a class hierarchy (I think)
The problem is Event needs to extend a class (Exception) that itself cannot extend anything. The methods (and properties) all pertain to "attribute" values, we'll call them "options" and "data", where "options" are values stored at class level, and "data" are values stored at instance level.
With exception of (no pun intended) the Exception class, I can simply create a common class that all pertinent objects extend in order to inherit the necessary functionality, but I'm wondering what I can do to avoid the seemingly inevitable code duplication in Event; also, other classes that are not conceptually similar enough to be siblings need this functionality.
So far the answer seems to be, using the object composition approach, create a Data class, and manage it at two points:
At object instantiation, create a Data instance to be used with the object as "data".
At some point (through a static initialize() method perhaps) create a Data instance to be used statically with the class as "options".
Interfaces, named IData and IOption for example, would be implemented by classes needing this functionality. IData simply enforces the instance methods of the Data class on the consumer, and calls would be forwarded to the instance Data property object, whereas IOption would enforce similarly named methods (substitute "data" for "option") and those methods would forward to the static Data property object.
What I'm looking at is something like this (the methods are somewhat naive in appearance, but I've slimmed them for brevity here):
interface IData{
public function setData($name, $value);
public function putData($name, &$variable);
public function getData($name = null);
}
interface IOption{
public static function initializeOptions();
public static function setOption($name, $value);
public static function setOptions(Array $options);
public static function getOptions($name = null);
}
class Data implements IData{
private $_values = array();
public function setData($name, $value){
$this->_values[$name] = $value;
}
public function putData($name, &$variable){
$this->_values[$name] = &$variable;
}
public function getData($name = null){
if(null === $name){
return $this->_values;
}
if(isset($this->_values[$name])){
return $this->_values[$name];
}
return null;
}
}
class Test implements IData, IOption{
private static $_option;
private $_data;
public static function initializeOptions(){
self::$_option = new Data();
}
public static function setOption($name, $value){
self::$_option->setData($name, $value);
}
public static function setOptions(Array $options){
foreach($options as $name => $value){
self::$_option->setData($name, $value);
}
}
public static function getOptions($name = null){
return self::$_option->getOptions($name);
}
public function __construct(){
$this->_data = new Data();
}
public function setData($name, $value){
$this->_data->setData($name, $value);
return $this;
}
public function putData($name, &$variable){
$this->_data->putData($name, $variable);
return $this;
}
public function getData($name = null){
return $this->_data->getData($name);
}
}
So where do I go from here? I can't shake the feeling that I'm moving away from good design with this; I've introduced an irreversible dependency between the client classes and the storage classes, which the interfaces can't explicitly enforce.
Edit: Alternatively, I could keep the reference to Data (wherever necessary) public, eliminating the need for proxy methods, thus simplifying the composition. The problem then, is that I cannot deviate from the Data class functionality, say for instance if I need to make getData() act recursively, as this snippet exemplifies:
function getData($name = null){
if(null === $name){
// $parent_object would refer to $this->_parent
// in the Test class, given it had a hierarchal
// implementation
return array_replace($parent_object->getData(), $this->_values);
}
// ...
}
Of course, this all boils down to separate definitions on a per-class basis, to support any deviation from a default implementation.
I suppose the end-all here, is that I'm having trouble understanding where code duplication is "alright" (or more accurately, unavoidable) and where I can extract common functionality into a container, and how to reference and use the contained functionality across classes, deviating (typically negligibly) where necessary. Again, traits (in my cursory testing on beta) seem to be a perfect fit here, but the principle of composition has existed long before 5.4 (and PHP entirely for that matter) and I'm certain that there is a "classic" way to accomplish this.
1. Interestingly, the page for multiple inheritance at Wikipedia has been flagged for copyright investigation. Diamond problem seemed like a fitting substitute.
EDIT: I've just read your question again and you seem to be suggesting that you are actually using the getters and setters to manipulate the data. If this is the case then could you provide me with more detail on what it is that you're trying to achieve. I suspect that how you've decided to model your objects and data is what has led you to this situation and that an alternative would solve the problem.
You don't need multiple inheritance. You don't even need most of the code you've written.
If the purposes of classes 'Data' and 'Option' is to simply store data then use an array. Or, if you prefer the syntax of an object cast the array to an object or an instance of stdClass:
$person = (object)array(
'name' => 'Peter',
'gender' => 'Male'
);
OR
$person = new stdClass;
$person->name = 'Peter';
$person->gender = 'Male';
Having a whole bunch of getters and setters that don't actually do anything to the data are pointless.
As the title says, I'm wanting to create an instance of a class from within a static method of the same class. I've figured out so far is that I can by doing something like this:
class Foo{
public $val;
public static function bar($val){
$inst = new Foo;
$inst->val = $val;
return $inst;
}
}
Which therefore lets me do this.
$obj = Foo::bar("some variable");
Which is great.
So now the questions. Is there an easier way of doing this that I'm not aware of, or any shortcuts to achieving the same result? Are there any advantages or disadvantages of creating an instance in this fashion?
Thanks.
They way you're doing it is fine. There are a few other things that can make your life easier that you can do as well.
Don't hardcode the class name. If you're on 5.3+, use the keyword static. That way, if you extend the class, the new function can instantiate that one as well:
public static function bar($var) {
$obj = new static();
$obj->var = $var;
return $obj;
}
Then you can use it in any extending class without needing to override anything.
Figure out if $var should be passed in through a constructor rather than set after construction. If the object depends upon it, you should require it.
public function __construct($var) {
$this->var = $var;
}
That way you can't instantiate the object without setting the variable.
Enforce the instantiation of the class through the static method. If you're doing anything in there that you need to do, then make the constructor either protected or private. That way, someone can't bypass the static method.
protected function __construct() {}
private function __construct() {}
Edit: Based on your comment above, it sounds to me like you're trying to implement the Singleton Design Pattern. There's tons of information out there about why it's not a great idea and the bad things it may do. It has uses as well.
But there are a few other patterns that may be of use to you depending on what you're doing exactly.
You can use the Factory Method if you're trying to create different objects using the same steps.
If all of the objects start off the same and then are customized, you could use the Prototype Pattern.
You could use an Object Pool if it's particularly expensive to create your object.
But one thing to consider, is that in PHP objects are pretty light weight. Don't try to avoid creating a new object just for that overhead. Avoid doing heavy things like database queries or filesystem accesses multiple times. But don't worry about calling new Foo() unless foo's constructor is particularly heavy...
This looks like a simple factory method pattern.
You have a nice advantage: suppose that in the future you want to start using a different implementation (but that does the same thing). Using a factory you can change all the objects that are created in many places of a complex system simply by changing the creator method. Note that this would work easier if you used an external class (as is in the first link below).
Keeping it as you have now, you can also subclass this class and override the method to create a more complex object. I don't think this is what you want to achieve in here.
Anyway, this is good to enable Test Driven Development, abstraction and lots of other good things.
links:
Php patterns
Factory method pattern on wikipedia
If you're just creating an object, this isn't very usefull. You could just call a constructor. But if you're doing something more complicated (like you're starting with some sort of singleton pattern but haven't included all the details in this example), then:
This sounds about right. If you want to prevent objects created in the default way like this:
$obj = new Foo("Some Variable");
You can add a private constructor:
class Foo{
public $val;
private __construct(){}
public static function bar($val){
$inst = new Foo;
$inst->val = $val;
return $inst;
}
}
Now you enforce people to use your static class. The need to set the val in the function might be gone, so you could even add the value-parameter to your private constructor but do the other things (that you presumably want to do, like check for some sort of singleton pattern) in your 'bar' function
Super late but found this useful.
A good example of this in the wild is this static method from Audi's UI library returning an Array of instantiated TextField classes from within TextField's static method upgradeElements.
/**
* Class constructor for Textfield AUI component.
* Implements AUI component design pattern defined at:
* https://github.com/...
*
* #param {HTMLElement} element The element that will be upgraded.
*/
export default class Textfield extends Component {
/**
* Upgrades all Textfield AUI components.
* #returns {Array} Returns an array of all newly upgraded components.
*/
static upgradeElements() {
let components = [];
Array.from(document.querySelectorAll(SELECTOR_COMPONENT)).forEach(element => {
if (!Component.isElementUpgraded(element)) {
components.push(new Textfield(element));
}
});
return components;
};
constructor(element) {
super(element);
}
...
See the rest in the repo
https://github.com/audi/audi-ui/blob/master/src/textfield/textfield.js#L25
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()
PHP object overloading is explained here.
Basically it allows you to define some custom actions when an inaccessible object property or method is accessed.
What are some practical uses for this feature?
Usually, those methods are useful when you are communicating with a 3rd party API or when the method/members structure is unclear.
Let's say you are writing a generic XML-RPC wrapper. Since you don't know the methods available to you before you download the WDL file, it makes sense to use Overloading.
Then, instead of writing the following:
$xmlrpc->call_method('DoSomething', array($arg1, $arg2));
You can use:
$xmlrpc->DoSomething($arg1, $arg2);
which is a more natural syntax.
You can also use member overloading in the same way as method overloading for variable objects.
Just one thing you want to watch for: limit its use only to variable-structure objects or use it only for syntactical shortcuts to getters and setters. It makes sense to keep getters and setters in your class to seperate business logic in multiple methods, but there is nothing wrong in using it as a shortcut:
class ShortcutDemo {
function &__get($name) {
// Usually you want to make sure the method
// exists using method_exists, but for sake
// of simplicity of this demo, I will omit
// that logic.
return call_user_method('get'.$name, $this);
}
function __set($name, &$value) {
return call_user_method('set'.$name, $this, $value);
}
private $_Name;
function &getName() { return $this->_Name; }
function setName(&$value) { $this->_Name = $value; }
}
That way you can continue using your getters and setters to validate and set your data, and still use the syntactic shortcuts as such:
$shortcut->Name = 'Hello';
Another method that Andrew didn't mention (or hasn't mentioned at the time of writing) is for getting rid of getters and setters. Instead of having to declare each setter and getter like this:
$obj->setName("Chacha");
$obj->setRep(10000000000000000000000);
You can instead just do
$obj->Name = "chacha";
$obj->Rep = 100000000000000000;
The second method is more natural.
Magic Methods basically further the thought of Object Oriented programming, and the idea that how you implement a job should not matter to the outside world. Through Magic Methods, it allows you to store your variables however you want, and just let other classes set them in a natural way.
Example: I could store all my user's account preferences in a single array that would make it really easy to iterate through to push it all up to the session.
If I didn't use a Magic Method for this, I would either have to make a bunch of sets or gets, which means writing more code, or allow direct access to the array, which reveals the implementation, so I can't go and change it later.
Instead, using Magic Methods, I just have them set the variable regularly, and I deal with it internally.
You could use it for cases when a class has complex rules for isset and unset. For example, a class containing a variable $a could be an array of objects or other resources, and when unset, they have to do perform some other functionalities.
Though I am not sure why they allow the adding of a new property and retrieving of a non-private property, but you could use it to change the internal state of an object by calling other code depending on the name of the property/member variable being set.
In some cases, this resembles operator overloading in C++
Message forwarding for when you have composed or aggregated objects where polymorphism isn't an option (say, you're using a library class you can't control).
<?php
// Class A is final, so we can't make subclasses.
final class A
{
public function hello( $callback )
{
echo call_user_func( $callback, 'hello world' );
}
}
// so instead, we make a wrapper class that will take an instance
// of A as an aggregate
class B
{
private $a;
public function __construct( A $a )
{
$this->a = $a;
}
// this mimics inheritance on the aggregate object
// method calls are automatically forwarded to instance of A
// if they are valid
public function __call( $method, $args )
{
if ( method_exists( $this->a, $method ) )
{
return call_user_func_array( array( $this->a, $method ), $args );
}
throw new Exception( "Method [$method] not found." );
}
}
class C extends B
{
// This mimics overriding an "inherited" method
public function hello( $callback )
{
echo call_user_func( $callback, 'bonjour le monde' );
}
}
$a = new A;
$b = new B( $a );
$c = new C( $a );
$b->hello( 'strtoupper' );
$c->hello( 'strtoupper' );
This feature is actually what object oriented programming is all about, in the mind of its inventor Alan Kay: Objects sending each other messages, and potentially reacting to any kind of message. Methods fixed at compile time are a limited (but also more efficient) implementation of this concept. That's where Kay's famous-quote "I invented the term object oriented, and I can tell you that C++ wasn't what I had in mind." comes from.
Basically, allowing objects to react to method calls without having a corresponding method fixed at compile time implements this original, broader definition of object orientation. Most modern "dynamic" languages support it in one form or another.
As for what it's good for: take a look at Groovy's Builders for a good example. Basically, it allows very compact low-redundancy syntax by turning method names themselves into data.
One way, which is quite a bit fancier, that I've used it is to create a Linq like Object Relational Management (ORM) system. Where you can then load up a database table structure and manipulated the data (from the database table) as if it were just an object.
i.e.
include('blibrary/bLinq.class.inc');
$linq = new bLinq(new bLinqSql('mysql://dsn'));
$r = $linq->from('Users')
->password
->select();
which translates to the following SQL:
SELECT `password` from Users;
The password in the select statement comes from the overloaded method.
The result can be used like:
(array)$r->password; // which outputs an array multiple results of password;
(string)$r->password; // which outputs a string of the first password hash;
$r->password[2]; // which outputs a string of the third password hash;
The point is that the word "password" could be substituted for any other field in the database on the fly when programming.
I use __get and __set to link objects together e.g.
$user = new User();
echo $user->Profile->views;
This (usually) calls some SQL linking users.id = profile.user_id.
Properties (like that in Python or C#). For example when you use something like this in Nette, you create some class, which shows some property as public:
<?php
class Foo extends Object
{
public $bar;
}
You can access this property natural way – $instance->bar. But when you want to do some validation etc., you just add getter and setter:
<?php
class Foo extends Object
{
private $bar;
public function getBar()
{
return $this->bar;
}
public function setBar($bar)
{
if ($bar === NULL) throw new Exception('…');
$this->bar = $bar;
}
}
And still you use $instance->bar. But when you do $instance->bar = NULL;, it's like calling $instance->setBar(NULL);.
I'm going to try something with the format of this question and I'm very open to suggestions about a better way to handle it.
I didn't want to just dump a bunch of code in the question so I've posted the code for the class on refactormycode.
base class for easy class property handling
My thought was that people can either post code snippets here or make changes on refactormycode and post links back to their refactorings. I'll make upvotes and accept an answer (assuming there's a clear "winner") based on that.
At any rate, on to the class itself:
I see a lot of debate about getter/setter class methods and is it better to just access simple property variables directly or should every class have explicit get/set methods defined, blah blah blah. I like the idea of having explicit methods in case you have to add more logic later. Then you don't have to modify any code that uses the class. However I hate having a million functions that look like this:
public function getFirstName()
{
return $this->firstName;
}
public function setFirstName($firstName)
{
return $this->firstName;
}
Now I'm sure I'm not the first person to do this (I'm hoping that there's a better way of doing it that someone can suggest to me).
Basically, the PropertyHandler class has a __call magic method. Any methods that come through __call that start with "get" or "set" are then routed to functions that set or retrieve values into an associative array. The key into the array is the name of the calling method after getting or setting. So, if the method coming into __call is "getFirstName", the array key is "FirstName".
I liked using __call because it will automatically take care of the case where the subclass already has a "getFirstName" method defined. My impression (and I may be wrong) is that the __get & __set magic methods don't do that.
So here's an example of how it would work:
class PropTest extends PropertyHandler
{
public function __construct()
{
parent::__construct();
}
}
$props = new PropTest();
$props->setFirstName("Mark");
echo $props->getFirstName();
Notice that PropTest doesn't actually have "setFirstName" or "getFirstName" methods and neither does PropertyHandler. All that's doing is manipulating array values.
The other case would be where your subclass is already extending something else. Since you can't have true multiple inheritances in PHP, you can make your subclass have a PropertyHandler instance as a private variable. You have to add one more function but then things behave in exactly the same way.
class PropTest2
{
private $props;
public function __construct()
{
$this->props = new PropertyHandler();
}
public function __call($method, $arguments)
{
return $this->props->__call($method, $arguments);
}
}
$props2 = new PropTest2();
$props2->setFirstName('Mark');
echo $props2->getFirstName();
Notice how the subclass has a __call method that just passes everything along to the PropertyHandler __call method.
Another good argument against handling getters and setters this way is that it makes it really hard to document.
In fact, it's basically impossible to use any sort of document generation tool since the explicit methods to be don't documented don't exist.
I've pretty much abandoned this approach for now. It was an interesting learning exercise but I think it sacrifices too much clarity.
The way I do it is the following:
class test {
protected $x='';
protected $y='';
function set_y ($y) {
print "specific function set_y\n";
$this->y = $y;
}
function __call($function , $args) {
print "generic function $function\n";
list ($name , $var ) = split ('_' , $function );
if ($name == 'get' && isset($this->$var)) {
return $this->$var;
}
if ($name == 'set' && isset($this->$var)) {
$this->$var= $args[0];
return;
}
trigger_error ("Fatal error: Call to undefined method test::$function()");
}
}
$p = new test();
$p->set_x(20);
$p->set_y(30);
print $p->get_x();
print $p->get_y();
$p->set_z(40);
Which will output (line breaks added for clarity)
generic function set_x
specific function set_y
generic function get_x
20
generic function get_y
30
generic function set_z
Notice: Fatal error: Call to undefined method set_z() in [...] on line 16
#Brian
My problem with this is that adding "more logic later" requires that you add blanket logic that applies to all properties accessed with the getter/setter or that you use if or switch statements to evaluate which property you're accessing so that you can apply specific logic.
That's not quite true. Take my first example:
class PropTest extends PropertyHandler
{
public function __construct()
{
parent::__construct();
}
}
$props = new PropTest();
$props->setFirstName("Mark");
echo $props->getFirstName();
Let's say that I need to add some logic for validating FirstNames. All I have to do is add a setFirstName method to my subclass and that method is automatically used instead.
class PropTest extends PropertyHandler
{
public function __construct()
{
parent::__construct();
}
public function setFirstName($name)
{
if($name == 'Mark')
{
echo "I love you, Mark!";
}
}
}
I'm just not satisfied with the limitations that PHP has when it comes to implicit accessor methods.
I agree completely. I like the Python way of handling this (my implementation is just a clumsy rip-off of it).
Yes that's right the variables have to be manually declared but i find that better since I fear a typo in the setter
$props2->setFristName('Mark');
will auto-generate a new property (FristName instead of FirstName) which will make debugging harder.
I like having methods instead of just using public fields, as well, but my problem with PHP's default implementation (using __get() and __set()) or your custom implementation is that you aren't establishing getters and setters on a per-property basis. My problem with this is that adding "more logic later" requires that you add blanket logic that applies to all properties accessed with the getter/setter or that you use if or switch statements to evaluate which property you're accessing so that you can apply specific logic.
I like your solution, and I applaud you for it--I'm just not satisfied with the limitations that PHP has when it comes to implicit accessor methods.
#Mark
But even your method requires a fresh declaration of the method, and it somewhat takes away the advantage of putting it in a method so that you can add more logic, because to add more logic requires the old-fashioned declaration of the method, anyway. In its default state (which is where it is impressive in what it detects/does), your technique is offering no advantage (in PHP) over public fields. You're restricting access to the field but giving carte blanche through accessor methods that don't have any restrictions of their own. I'm not aware that unchecked explicit accessors offer any advantage over public fields in any language, but people can and should feel free to correct me if I'm wrong.
I've always handled this issue in a similar with a __call which ends up pretty much as boiler plate code in many of my classes. However, it's compact, and uses the reflection classes to only add getters / setters for properties you have already set (won't add new ones). Simply adding the getter / setter explicitly will add more complex functionality. It expects to be
Code looks like this:
/**
* Handles default set and get calls
*/
public function __call($method, $params) {
//did you call get or set
if ( preg_match( "|^[gs]et([A-Z][\w]+)|", $method, $matches ) ) {
//which var?
$var = strtolower($matches[1]);
$r = new ReflectionClass($this);
$properties = $r->getdefaultProperties();
//if it exists
if ( array_key_exists($var,$properties) ) {
//set
if ( 's' == $method[0] ) {
$this->$var = $params[0];
}
//get
elseif ( 'g' == $method[0] ) {
return $this->$var;
}
}
}
}
Adding this to a class where you have declared default properties like:
class MyClass {
public $myvar = null;
}
$test = new MyClass;
$test->setMyvar = "arapaho";
echo $test->getMyvar; //echos arapaho
The reflection class may add something of use to what you were proposing. Neat solution #Mark.
Just recently, I also thought about handling getters and setters the way you suggested (the second approach was my favorite, i.e. the private $props array), but I discarded it for it wouldn't have worked out in my app.
I am working on a rather large SoapServer-based application and the soap interface of PHP 5 injects the values that are transmitted via soap directly into the associated class, without bothering about existing or non-existing properties in the class.
I can't help putting in my 2 cents...
I have taken to using __get and __set in this manor http://gist.github.com/351387 (similar to the way that doctrine does it), then only ever accessing the properties via the $obj->var in an outside of the class. That way you can override functionality as needed instead of making a huge __get or __set function, or overriding __get and __set in the child classes.