Static wrapper class
Fun and games with magic methods
PHP 5.3.0 introduced a new magic method that can be overloaded to provide extra functionality to your classes: __callStatic()
Like the __call() method it acts as a catch-all method for undefined function calls, the difference being that __call catches undefined dynamic calls, whereas __callStatic catches static calls.
Here's an example:
<?
class Test
{
public static function myStatic()
{
echo "Regular call to myStatic()";
}
public function myDynamic()
{
echo "Regular call to myDynamic()";
}
public function __call($name, $arguments)
{
echo "Call to undefined function $name";
}
public function __callStatic($name, $arguments)
{
echo "Static call to undefined function $name";
}
}
$t = new Test();
$t->myDynamic();
$t->somethingElse();
Test::myStatic();
Test::somethingElse();
?>
The output for this script is:
Regular call to myDynamic()
Call to undefined function somethingElse
Regular call to myStatic()
Static call to undefined function someOtherStatic
Wrapping around objects
The following example shows a class that wraps around an instance of the PDO database access layer and reroutes any unknown static calls to its internal $pdo object.
<?
class DB
{
private static $pdo;
/**
* Initialises this connection
*/
public static function connect($host, $user, $pass, $dbname)
{
if (isset(self::$pdo))
throw new Exception('Database already connected');
self::$pdo = new PDO('mysql:host='.$host.';dbname='.$dbname, $user, $pass);
}
/**
* Any undefined static calls are routed to the internal PDO object
*/
public static function __callStatic($method, $arguments)
{
if (!isset(self::$pdo))
throw new Exception('Database not connected');
return call_user_func_array(array(self::$pdo, $method), $arguments);
}
// Your methods go here
}
?>
Here's an example of its usage:
<?
DB::connect('localhost', 'michael', 'verySecret', 'test');
$q = DB::query('SELECT * FROM user WHERE id = 1');
var_dump($q->fetch());
?>
So why would you do this?
Global access: the DB wrapper provides global access to a single PDO instance.
Openness: the reason I'm using this technique myself is that it allows me to build a central DB abstraction layer (based on PDO) but without enforcing other parts of the code to access the DB through it.
Because you can: the above example has a lot of shortcomings, but it's novel, and messing around with techniques like these might lead to something better.
Some obvious shortcomings
Naming conflicts: The wrapper class and the 'extended' class share the same namespace, so defining a (static) method in the wrapper class with the same name as a PDO method will overload this method.
Autocompletion: Your IDE won't be able to fill in suggestions for DB:: that aren't explicitly defined somewhere.
Feb 27th, 2010
Comments
No comments yet! Feel free to post some using the form below.
If you wish to add code to your comment you can use code tags, like this: <code class="php">yourCodeHere</code>.
Quite a large number of languages are supported, although I can't guarantee it'll be pretty. Inside the code tags you can use any characters except for the string "</code>".