HomePHP Page 3 - Overloading and Object-Oriented Programming with PHP 5
_ _call() - PHP
Last week, we discussed design patterns and polymorphism. This week, we examine overloading and more. This article, the last of four parts, is excerpted from chapter two of the book Advanced PHP Programming, written by George Schlossnagle (Sams; ISBN: 0672325616).
PHP also supports method overloading through the _ _call() callback. This means that if you invoke a method of an object and that method does not exist, _ _call() will be called instead. A trivial use of this functionality is in protecting against undefined methods. The following example implements a _ _call() hook for a class that simply prints the name of the method you tried to invoke, as well as all the arguments passed to the class:
class Test {
public function _ _call($funcname, $args)
{
print "Undefined method $funcname called with
vars:\n";
print_r($args);
}
}
If you try to execute a nonexistent method, like this:
$obj = new Test;
$obj->hello("george");
you will get the following output:
Undefined method hello called with vars:
Array
(
[0] => george
)
_ _call() handlers are extremely useful in remote procedure calls (RPCs), where the exact methods supported by the remote server are not likely to know when you implement your client class. RPC methods are covered in depth in Chapter 16, "RPC: Interacting with Remote Services." To demonstrate their usage here briefly, you can put together an OO interface to Cisco routers. Traditionally, you log in to a Cisco router over Telnet and use the command-line interface to configure and maintain the router. Cisco routers run their own proprietary operating system, IOS. Different versions of that operating system support different feature sets and thus different command syntaxes. Instead of programming a complete interface for each version of IOS, you can use _ _call() to automatically handle command dispatching.
Because the router must be accessed via Telnet, you can extend PEAR's Net_Telnet class to provide that layer of access. Because the Telnet details are handled by the parent class, you only need two real functions in the class. The first, login(), handles the special case of login. login() looks for the password prompt and sends your login credentials when it sees the password prompt.
PEAR - PHP Extension and Application Repository (PEAR) is a project that is loosely associated with the PHP group. Its goal is to provide a collection of high-quality, OO, reusable base components for developing applications with PHP. Throughout this book, I use a number of PEAR classes. In both this book and my own programming practice, I often prefer to build my own components. Especially in performance-critical applications, it is often easiest to design a solution that fits your exact needs and is not overburdened by extra fluff. However, it can sometimes be much easier to use an existing solution than to reinvent the wheel.
Since PHP 4.3, PHP has shipped with a PEAR installer, which can be executed from the command line as follows:
> pear
To see the full list of features in the PEAR installer you can simply type this:
> pear help
The main command of interest is pear install. In this particular case, you need the Net_Telnet class to run this example. To install this class, you just need to execute this:
> pear install Net_Telnet
You might need to execute this as root. To see a complete list of PEAR packages available, you can run this:
The second function you need in the Net_Telnet class is the _ _call() handler. This is where you take care of a couple details:
Many Cisco IOS commands are multiword commands. For example, the command to show the routing table is show ip route. You might like to support this both as $router->show_ip_route() and as $router->show("ip route"). To this end, you should replace any _ in the method name with a space and concatenate the result with the rest of the arguments to make the command.
If you call a command that is unimplemented, you should log an error. (Alternatively, you could use die() or throw an exception. Chapter 3 covers good error-handling techniques in depth.)
Here is the implementation of Cisco_RPC; note how short it is, even though it supports the full IOS command set: