Late Static Binding with PHP 5.3

With the Alpha3 Release of PHP 5.3 out and about it’s looking like the much anticipated late static binding functionality is starting to solidify. Once I finally got PHP 5.3 running (see my previous post) I worked through creating an  ActiveRecord-like class to see if I could make a PHP object do act in a similar way  similar to Ruby’s Active Record.

Lets see where I ended up…

class ActiveRecord {
  public static function find($id){
    $called_class = get_called_class(); //a new function as of a2
    return new $called_class();
  }
  //A derived example to show the late static binding in action
  public static function testLSB(){
    return static::$table;
  }
}
class BasicModel extends ActiveRecord {
  public static $table = 'basicModel';
}
//Output examples
echo get_class(BasicModel::Find(1)); //Output - BasicModel
echo BasicModel::testLSB();          //Output - basicModel
echo BasicModel::$table;             //Output - basicModel
First place I saw the get_called_class() method was on the PHP Late Static Binding Manual Page

The above example is celarly a bit derived, but I’m quite excited at where this is heading. I still have a bit of work to do if I want to end up accessing all my models in the Rails/Active Record fashion.

$user = new User(1); //by passing a user id directly to the constructor
$user = User::Find(1); //by static::find();
$users = Users::FindAll(); //by static::findAL() returning an array of User objects.

I don’t see these requirements too difficult to achieve but it will require some trickery. The problem will lie if I decide to put all the database logic into static::Find(). If static::Find() returns a new instance of the class, and the constructor of each class blindly returns the results of a static::Find() call, it won’t work. The code below  doesn’t work because a constructor can’t return a new object instance and $this can’t be reassigned (like you can in some languages).

public function __construct($id){
 if (is_array($id)){
    $this->data = $id;
  }else{
    $this = static::find($id); //fatal error, can't reassign $this
    return static::find($id); //also won't do anything useful
  }
}

From fist impressions I think the idea of using is_array() to check if the $id parameter is a good way for static::Find() to pass an array to the constructor without ending up in a loop. This suggests that there needs to be a similar check inside static::Find() to return only an array in some cases instead of a new object.

So I’ve come up with this idea to solve the above issue.

public function __construct($id){
 if (is_array($id))
    $this->data = $id;
 else
    $this->data = static::find($id,true); //static::find() returns an array;
}
public static function Find($id,$returnArray = false){
  $foundResults = insert_SQL_function_here();
  if ($returnArray === true)
    return $foundResults; //return basic array
  else{
    $called_class = get_called_class();
    return new $called_class($foundResults);
  }
}

I’m not 100% convinced this is the best way to solve this. Ideally I’d like a solution that didn’t require the checks in __construct() and static::find(), but this is a start, and it’s a a reasonable exercise in using LSB.

Share this article:
  • Digg
  • del.icio.us
  • Facebook
  • Google Bookmarks
  • LinkedIn
  • DZone
  • Furl
  • Ma.gnolia
  • NewsVine
  • Reddit
  • Slashdot
  • StumbleUpon
  • Technorati
This entry was posted in Programming and tagged , . Bookmark the permalink.

Leave a Reply