tags:

views:

239

answers:

8

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?

+3  A: 

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';
Andrew Moore
A: 

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.

Chacha102
Though I wouldn't get rid of getters and setters just yet. Multiple methods containing business rules for the various individual properties is usually easier to maintain and debug then one huge method containing all the business rules for all properties. I would just use `__get()` and `__set()` for a shortcut way to call `getX`, `setX`. Object overloading use must be kept only for variable structure objects.
Andrew Moore
Read my updated version.
Chacha102
However, this doesn't really work like C# Get/Set Property. At least not as flexible, if you wish to verify or validate what is being set.
Extrakun
A: 

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++

Extrakun
A: 

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' );
Peter Bailey
A: 

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.

Michael Borgwardt
A: 

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.

null
A: 

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.

Question Mark
A: 

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);.

Jakub Kulhan