PHP - override function with different number of parameters - php

I'm extending a class, but in some scenarios I'm overriding a method. Sometimes in 2 parameters, sometimes in 3, sometimes without parameters.
Unfortunately I'm getting a PHP warning.
My minimum verifiable example:
http://pastebin.com/6MqUX9Ui
<?php
class first {
public function something($param1) {
return 'first-'.$param1;
}
}
class second extends first {
public function something($param1, $param2) {
return 'second params=('.$param1.','.$param2.')';
}
}
// Strict standards: Declaration of second::something() should be compatible with that of first::something() in /home/szymon/webs/wildcard/www/source/public/override.php on line 13
$myClass = new Second();
var_dump( $myClass->something(123,456) );
I'm getting PHP error/warning/info:
How can I prevent errors like this?

you can redefine methods easily adding new arguments, it's only needs that the new arguments are optional (have a default value in your signature). See below:
class Parent
{
protected function test($var1) {
echo($var1);
}
}
class Child extends Parent
{
protected function test($var1, $var2 = null) {
echo($var1);
echo($var1);
}
}
For more detail, check out the link: http://php.net/manual/en/language.oop5.abstract.php

Another solution (a bit "dirtier") is to declare your methods with no argument at all, and in your methods to use the func_get_args() function to retrieve your arguments...
http://www.php.net/manual/en/function.func-get-args.php

As of PHP 8.1, there's a cool hack to override a class's method with extra number of required arguments. You should use the new new in initializers feature. But how?
We define a class having a constructor always throwing a ArgumentCountError, and make it the default value of every extra required parameter (an improved version of #jose.serapicos's answer). Simple and cool!
Now let's see it in action. First, we define RequiredParam:
final class RequiredParameter extends \ArgumentCountError
{
public function __construct()
{
// Nested hack
throw $this;
}
}
And then:
class Base
{
public function something(string $baseParam): string
{
return $baseParam;
}
}
class Derived extends Base
{
public function something(
string $baseParam,
string|RequiredParameter $extraParam = new RequiredParameter(),
): string {
return "$baseParam + $extraParam";
}
}
This way, no one can bypass the extra parameters, because RequiredParameter is declared as final. It works for interfaces as well.
How Good or Bad is This?
One advantage is that it's a little more flexible than setting default parameters as null, as you can pass the constructor of RequiredParameter an arbitrary list of parameters and probably build a custom error message.
Another advantage is that it's handled less manually, and thus being more safe. You may forget about handling a null value, but RequiredParameter class handles things for you.
One major disadvantage of this method is that it breaks the rules. First and foremost, you must ask yourself why you would need this, because it breaks polymorphism in most cases. Use it with caution.
However, there are valid use cases for this, like extending parent class's method with the same name (if you cannot modify the parent, otherwise I recommend you to use traits instead), and using the child class as standalone (i.e. without the help of parent class's type).
Another disadvantage is that it requires you to use union types for each parameter. While the following workaround is possible, but it requires you to create more classes, which may hurt understandability of your code, as well as having little impact on maintainability and performance (based on your conditions). BTW, no hack comes for free.
Eliminating the use of Union Type
You could extend from or implement RequiredParameter the compatible type of the actual parameter to be able to remove the need for union type:
class BaseRequiredParameter extends Base
{
public function __construct()
{
throw new \ArgumentCountError();
}
}
class Derived extends Base
{
public function something(
string $baseParam,
Base $extraParam = new BaseRequiredParameter()
): string {
return "$baseParam + {$extraParam->something()}";
}
}
It's also possible for strings, if you implement the Stringable interface (e.g. Throwable implements it by default). It doesn't work for some primitive types including bool, int, float, callable, array, etc., however, if you're interested, you're still able to use some alternatives like Closure or Traversable.
For making your life easier, you may want to define the constructor as a trait and use it (I'm aware of this answer, but in fact, this is a valid useful case for a constructor in a trait, at least IMO).

Your interface/abstract class or the most parent class, should cotantin the maximum number of params a method could recieve, you can declare them explicitely to NULL, so if they are not given, no error will occur i.e.
Class A{
public function smth($param1, $param2='', $param3='')
Class B extends A {
public function smth($param1, $param2, $param3='')
Class C extends B {
public function smth($param1, $param2, $param3);
In this case, using the method smth() as an object of 'A' you will be obligated to use only one param ($param1), but using the same method as object 'B' you will be oblgiated to use 2 params ($param1, $param2) and instanciating it from C you have to give all the params

Related

OOP (PHP) - Force overridden method to call according parent-method

I have a general problem with this use case: I have a class A. This class has a non-abstract method doStuffCallback() which could be overridden but it's not necessary for every subclass. But: I want to ensure that if the method is overriden the subclass-method must call the parents method.
Example:
abstract class A {
private function doStuff() {
$this->doStuffCallback();
}
protected function doStuffCallback() {
// IMPORTANT CODE HERE
}
}
class B extends A {
protected function doStuffCallback() {
parent::doStuffCallback(); // I want to enforce this because the parents method code is important
// ALSO IMPORTANT CODE
}
}
Because the overridden method does the same thing it would be very ugly to define two methods for the same responsibility and a private helper-method which calls both. Like this:
abstract class A {
private function doStuff() {
$this->callDoStuffCallback();
}
private function callDoStuffCallback() {
$this->internalDoStuffCallback();
$this->doStuffCallback();
// This is VERY ugly
}
private function internalDoStuffCallback() {
// IMPORTANT CODE HERE
}
protected function doStuffCallback() {}
}
class B extends A {
protected function doStuffCallback() {
// IMPORTANT CODE
}
}
This is really ugly and laborious. So my question: Is there a way in PHP to force overriden methods to call the parents method?
No. There is no such language feature in PHP; this restriction is not possible in most subtype-'OO' languages.
Instead programs must rely on explicit documentation contracts; and hopefully, unit testing to ensure conformance.
Guards may also be employed such that, at some point by and by when a method on the parent class is used, it could throw an exception if the 'current state' is not valid (eg. such and such a method has not been called yet). This may also be made more explicit by making the subclass required to call (as defined in the documentation contract) some special method, instead of simply the overriden super method. However, such is outside of any type system.
While the self:: scope could be used (eg. call non-overriden method which calls overriden method), this would involve further magic (eg. some stack state) to avoid infinite recursion loops; and it would be as easy to accidentally omit usage.
My recommendation is to call a (private) method that calls this 'maybe overriden' method in relationship to whatever logic applies, as shown in the example (although hopefully with more task specific tames). Then the (protected) overriden method is not expected or required to handle any of the special logic itself; nor is it meant to be called directly outside of the context established by the parent class - it is just what it currently claims to be, a special callback.
I tend to disagree with "This is VERY ugly". It is the standard way of handling this use case and a variant of the Template Method Pattern.
Now I am just guessing because you did not provide a real example but if you say that the two methods "do the same thing", there might be something wrong with your design. If they do the same thing, why is calling the parent implementation necessary if the subclass does the same thing in a different way? To me it sounds like the method actually does more than one thing and you might be able to break it down into several parts that can be overridden individually (or not, then make them private or final).
I know this is an old topic but I was asking myself the same question and what I did is :
abstract class A {
private function doStuff() {
$this->doStuffCallback();
}
final protected function doStuffCallback() {
// IMPORTANT CODE HERE
$this->callNewFunction();
}
abstract protected function callNewFunction();
}
class B extends A {
protected function callNewFunction() {
// ALSO IMPORTANT CODE
}
}
So basically I would mark as "final" the function you wish to force the code for every child and then call a new "Abstract" function to force the childs to implement it. If you do not wish to force the new "Abstract" function, simply don't make it abstract.
Edit : This is basically #Fabian Schmengler's answer but more concrete with your example.
No, you can access, you can use method for parent, like this
<?php
class A {
function s1($p1) {
echo 's1: '.$p1;
}
}
class B extends A {
public function callParent($method, $p1) {
parent::$method($p1);
}
}
$b = new B();
$b->callParent('s1', 'param1');
or replace extending on magic methods __call and etc. https://github.com/StagnantIce/php_extend_magic/blob/master/AExtendClass.php

Snookered by abstract - PHP

I have an abstract class I am inheriting from:
abstract class Test
{
public function GetTests()
{
}
}
and I have a concrete that I have been using the abstract classes implementation for most of the time:
class Concrete extends Test
{
// No problemmos
}
I recently had to implement a different version of the GetTests method, and in fact I wanted to overwrite it as it's built into all of my routing:
class Concrete extends Test
{
public function GetTests( $newArgument )
{
// notice $newArgument
}
}
However I get this error message:
Declaration of Concrete::GetTests() should be compatible with Test::GetTests()
Apart from copying the entirety of the functions from the abstract class for this concrete, even though I only need to implement this one method differently... Is there a way of getting around this?
I do understand that I could have:
abstract class Test
{
abstract public function GetTests();
}
But this is why I am snookered, because I no longer have the ability to modify how the underlying Test class is implemented... doh!... Unless I really have to..
Thanks to all great answers...
I have decided to de snooker myself (it's going to hurt but it's going to be worth it) and I will instantiate the Test class inside the Concrete class, implement concrete versions of all the Test class methods, and then inside them just call the instantiated Test class... This means in the future (or indeed now) I can simply not call that feature...
For context:
/* no longer abstract */ class UnitOfWorkController
{
public function GetUnits()
{
// Implementation
return View::make(...);
}
}
and...
class SomethingController /* no longer extends the UnitOfWorkController */
{
private $unitOfWorkController;
public function __Construct()
{
$this->unitOfWorkController = new UnitOfWorkController();
}
public function GetUnits()
{
return $this->unitOfWorkController->GetUnits();
// or I could just implement my own junk
}
}
Your concrete subclass is in violation of the Liskov Substitution Principle, which to cut a long story short says that if an object of class X can be processed by a given piece of code, then every possible subclass of X must also be able to be processed by the same piece of code.
Say I wanted to make another subclass of Test and wanted to implement my own GetTests method. The base class method doesn't accept any arguments at all, so that suggests that, if my subclass is to be substitutable for its superclass, my implementation of that method cannot take any arguments either. If I give my implementation arguments, then it no longer conforms to the specification as laid down by the superclass.
If I have code that does:
$object = new Test;
$test -> GetTests ();
then I can't substitute my subclass of Test without also changing the calling code to pass in an argument. Likewise if I do change it, then I have another subclass of Test that doesn't require an argument for GetTests then the code would have to change again. In fact the same code simply can't be used as is with both subclasses without having to jump through some hoops to determine the actual class and using the appropriate calling convention which means needing to know things about the class I'm about to use that I shouldn't need to know.
PHP is less strict than most OO languages about subclass method signitures matching their superclass, but it will issue a warning if they don't match. The only way to fix the warning is to have all subclasses have the same method signatures as the superclass they inherit from.
Child methods must have the same signature as the same method in a parent class. This includes required parameters and their typecasting.
For example, a child class of the following method must also have one parameter, and the parameter must cast to the ArgumentType class or a child of thereof.
public function something(ArgumentType $Argument)
{
}
You can, however, make the parameter optional by setting it to null or any other value:
public function something(ArgumentType $Argument = null)
{
}
In this case, child methods may omit this parameter.
From the PHP docs, see http://php.net/manual/en/language.oop5.abstract.php:
[…] Furthermore the signatures of the methods must match, i.e. the type hints and the number of required arguments must be the same. For example, if the child class defines an optional argument, where the abstract method's signature does not, there is no conflict in the signature.
The method signature of Concrete::GetTests() has a variable while Test::GetTests() does not. Since you have already defined this method within Test, it is now being inherited. The inherited version is not compatible with your overridden version.
Here are your options:
Add $newArgument to the parameters list in Test::GetTests().
Remove $newArgument from the parameters list in Concrete::GetTests().
Rename Concrete::GetTests() to something else.
PHP does not support this, as the error message says. If you want to override the function, it has to have the same footprint, which in your case it doesn't
What you could do is use a magic method: http://php.net/manual/en/language.oop5.overloading.php#object.call
the parameter array is a separate entity, so you 'decide' in your code (which you can override) what to do with which parameter.
I wanted to link a blog I read about this, but couldn't find the one I was thinking of. There is this rather strangely formatted one, not sure if it any good, but it does touch on some of the issues.
You could obviously add the argument to the parent, but this is 'leaking' upwards. If other childeren want even more, you'd get a big party of random paramteres that all can be nulled.

Cast derived class to base class in php

I'm probably missing something obvious here as this is basic functionality in other OOP languages, but I'm struggling with PHP way of doing this. I understand that PHP is not "true" OOP language, but still...
What I'm after is casting an object instantiated as derived class to base class. Something along the lines of:
class Some{}
class SomeMock extends Some {}
function GetSomeMock(){
$mock = new SomeMock();
return (Some)$mock; //Syntax error here
}
I've found some questions with strange request of downcasting objects of base class to derived which is possible with some nasty tweaks, but this basic functionality does not have to be that difficult. What am I missing here?
Edit: It seems that it's always matter what I'm trying to achieve. No problem. GetSomeMock() is a factory method that would return a mock object stub (derived from base class, all properties prepopulated in constructor) with expected properties' values. I would then compare it to another object of base type that is restored from database:
$this->assertEquals($mockObject, $realObject);
This fails instantly as $mockObject and $realObject are of different types. I can imagine there are many workarounds I can implement to achieve the same, but I'd like to keep things as simple as possible.
Ok, the short answer seems to be: This is not possible. PHP knows better than me what type I need.
In PHP you cannot cast to a specific class, I cannot even see any need for that.
You may cast to some native type - string, int, array, object. But not a specific class.
If you need to use some functionality of a base class, you can do it via parent keyword.
class Some {
public function execute(){
echo "I am some" ;
}
}
class SomeMock extends Some {
public function execute(){ //Override the function
parent::execute() ; //Here you can execute parent's functionality and add some more
}
}
Edit:
instanceof operator may come handy. When comparing objects.
For instance:
$object = new SomeMock() ;
$status = ($object instanceof Some && $object instanceof SomeMock); //will return true here ;
Child classes inherit non-private properties and methods.
Let's say, you have your function:
function assertEquals($mockObject, $realObject){
if ($mockObject instanceof Some && $realObject instanceof Some){
//Both objects have the same base class - Some
//That means they must have inherited the functionality and properties of Some class.
}
}
You can do it with an custom function:
private function castParameter(BaseClass $parameters) : DerivedClass {
return $parameters;
}
I did come across use cases when I needed to cast a derived class to its base class. I did the following.
function castToParentClass($derivedClassInstance) {
$parentClassName = get_parent_class($derivedClassInstance);
$parentClassInstance = new $parentClassName();
foreach ($parentClassInstance as $key => $value) {
$parentClassInstance->{$key} = $derivedClassInstance->{$key};
}
return $parentClassInstance;
}

When would you need to use late static binding?

After reading this description of late static binding (LSB) I see pretty clearly what is going on. Now, under which sorts of circumstances might that be most useful or needed?
I needed LSB this for the following scenario:
Imagine you're building a "mail processor" daemon that downloads the message from an email server, classifies it, parses it, saves it, and then does something, depending on the type of the message.
Class hierarchy: you have a base Message class, with children "BouncedMessage" and "AcceptedMessage".
Each of the message types has its own way to persist itself on disk. For example, all messages of type BouncedMessage try to save itself as BouncedMessage-id.xml. AcceptedMessage, on the other hand, needs to save itself differently - as AcceptedMessage-timestamp.xml. The important thing here is that the logic for determining the filename pattern is different for different subclasses, but shared for all items within the subclass. That's why it makes sense for it to be in a static method.
Base Message class has an abstract static method (yes, abstract AND static) "save". BouncedMessage implements this method with a concrete static method. Then, inside the class that actually retrieves the message, you can call "::save()"
If you want to learn more about the subject:
http://www.qcodo.com/forums/topic.php/2356
http://community.livejournal.com/php/585907.html
http://bugs.php.net/bug.php?id=42681
One primary need I have for late static binding is for a set of static instance-creation methods.
This DateAndTime class is part of a chronology library that I ported to PHP from Smalltalk/Squeak. Using static instance-creation methods enables creation of instances with a variety of argument types, while keeping parameter checking in the static method so that the consumer of the library is unable to obtain an instance that is not fully valid.
Late static binding is useful in this case so that the implementations of these static instance-creation methods can determine what class was originally targeted by the call. Here is an example of usage:
With LSB:
class DateAndTime {
public static function now() {
$class = static::myClass();
$obj = new $class;
$obj->setSeconds(time());
return $obj;
}
public static function yesterday() {
$class = static::myClass();
$obj = new $class;
$obj->setSeconds(time() - 86400);
return $obj;
}
protected static function myClass () {
return 'DateAndTime';
}
}
class Timestamp extends DateAndTime {
protected static function myClass () {
return 'Timestamp';
}
}
// Usage:
$date = DateAndTime::now();
$timestamp = Timestamp::now();
$date2 = DateAndTime::yesterday();
$timestamp2 = Timestamp::yesterday();
Without late static binding, [as in my current implementation] each class must implement every instance creation method as in this example:
Without LSB:
class DateAndTime {
public static function now($class = 'DateAndTime') {
$obj = new $class;
$obj->setSeconds(time());
return $obj;
}
public static function yesterday($class = 'DateAndTime') {
$obj = new $class;
$obj->setSeconds(time() - 86400);
return $obj;
}
}
class Timestamp extends DateAndTime {
public static function now($class = 'Timestamp') {
return self::now($class);
}
public static function yesterday($class = 'Timestamp') {
return self::yesterday($class);
}
}
As the number of instance-creation methods and class-hierarchy increases the duplication of methods becomes a real pain in the butt. LSB reduces this duplication and allows for much cleaner and more straight-forward implementations.
It's useful when:
You have functionality that varies over the class hierarchy,
The functionality has the same signature over the hierarchy, and
(crucially) You don't have an instance to hang the functionality off of.
If only #1 and #2 obtained, you would use an ordinary instance method. So Alex's problem (see his answer to this question) does not require LSB.
A typical case is object creation, where subclasses create themselves in different ways, but using the same parameters. Obviously you have no instance to call, so the creation method (also known as a factory method) must be static. Yet you want its behavior to vary depending on the subclass, so an ordinary static method is not right. See Adam Franco's answer for an example.
If you need to access an overloaded static property/Method within a method that hasn't been overloaded in a subclass - you need late static binding. A quick example: paste2.org
The classic example is the ActiveRecord class from Rails, if you try to implement something similar in PHP, which would look like this: class User extends ActiveRecord and then try to call User::find(1) the method that gets called is actually ActiveRecord::find() because you haven't overloaded find() in User - but without late static binding the find() method in ActiveRecord has no way of knowing which classed it got called from (self within it will always point to ActiveRecord), and thus it can't fetch your User-object for you.
Suppose you have classes representing tables (row instances) in a simplified object-relational mapper.
You would have a class "User" and a class "Company" who's instances are representing rows of the respective tables.
User and Company would inherit from some base abstract class, let's say "BaseObject" that will have some common methods like save(), delete(), validate() etc ...
If you want to store data about the validation and the table definition, the best place would be in a static variable in each derived class - since the validation and table definition is the same for each instance of User.
Without LSB the mentioned validate() method in BaseObject would have no reference to the static variables defined in User and Company, even though you are calling it through an instance of User. It will look for the same static variable in the BaseObject class, and it will raise an error.
This is my experience with PHP 5.2.8 - LSB is going to be introduced in 5.3
I have a class with a static method that handles some formatting. I have another class that than needs all the functionality of the original one except for how it handles formatting.

Is this a reasonable way to handle getters/setters in a PHP class?

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.

Categories