Saturday, August 26, 2006

Observers and Subjects

The most well-known design pattern for decoupling object instances or classes from one another and still have a mechanism for the observer to know, when a particular event occurs on a subject, is the Observer-Pattern. The implementation is typically done either using abstract classes or using interfaces.

While the prior has the advantage that the abstract classes may provide a reusable behaviour for observer registration and notification it limits an observer to stay in the observer role. It's not possible for an observer of one subject, to act as a subject itself (unless, you are relying on implicit coding/naming conventions rather than on an explicit mechanism). While this may not be a problem with languages allowing multiple inhertiance, it is for languages that support single inheritance only.

The latter (inteface-based) approach, releaves you of this issue at the cost of implementing the required methods on every class that wants to make use of the pattern. While this may be inconvenient it is a valid means to resolve and works most of the time.

With dynamic languages such as PHP or JavaScript there is yet another way to approach the issue using a mediating class that organizes the eventhandling between abitrary objects (or classes or basically any entity you may think of). Let's show an example for the usage of this approach:

class Event { ... }


class Subject {

 public function doSomething() {
  //do something and throw the event
  Event::raise($this,'onDoSomething');
 }

}


class Observer {

 public function onEvent(Event $event) {
  //react to the event
  echo get_class($event->getSourceObject());
 }

}

$subject = new Subject();
$observer = new Observer();
Event::register($subject,'onDoSomething',$observer,'onEvent');
$subject->doSomething(); //prints 'Subject'

What you are now probably interested in the most is the implementation of the "Event"-class. As you have seen there are two static methods on it:

1) register() allows to register abitrary methods or functions to be registered as callbacks for a particular event - 'onDoSomething' in this case - of objects or classes (the latter is not yet supported by the following implementation)

2) raise() allows to indicate the occurrence of a particular event on an object or class (the latter is not yet supported by the following implementation). All previously registered callback methods (you may as well call them the observers) will be executed using a single argument: an "Event"-object instance.

This object may be used to query for particular aspects of the event happening using one of the following methods.

1) getSourceObject() returns the subject the event occurred on if existing

2) getName() returns the name of the event so that the observer may decide how to handle different types of events, if this is not already distinguished using different callback methods.

3) getTargetObject() returns a reference to the observer if it is an object instance

4) getTargetMethod() returns the name of the callback method

5) getParameters() return an array of additional parameters that the subject may hand over to raise().

A possible implementation of the "Event"-class may look shown below. Please note that this version currently only supports object-to-object event handling:

class Event {

    protected $targetObject;
    protected $targetMethod;
    protected $eventName;
    protected $sourceObject;
    protected $parameters;

    protected function __construct($targetObject,
                                   $targetMethod,
                                   $eventName,
                                   $sourceObject,
                                   array $parameters = array()) {
        $this->targetObject = $targetObject;
        $this->targetMethod = $targetMethod;
        $this->eventName = $eventName;
        $this->sourceObject = $sourceObject;
        $this->parameters = $parameters;
    }

    public function getSourceObject() {
        return $this->sourceObject;
    }

    public function getName() {
        return $this->eventName;
    }

    public function getTargetMethod() {
        return $this->targetMethod;
    }

    public function getTargetObject() {
        return $this->targetObject;
    }

    public function getParameters() {
        return $this->parameters;
    }

    public static function raise($onObject,
                                 $event,
                                 array $parameters = array()) {
        foreach($onObject->__eventRegistry[$event] as $target) {
            if($target[0]) {
                call_user_func_array($target,
                                     array(
                                         new Event(
                                             $target[0],
                                             $target[1],
                                             $event,
                                             $onObject,
                                             $parameters)
                                     )
                );
            } else {
                call_user_func_array($target[1],
                                     array(
                                         new Event(
                                             NULL,
                                             $target[1],
                                             $event,
                                             $onObject,
                                             $parameters)
                                     )
                );
        }
    }

    public static function register($sourceObject,
                                    $forEvent,
                                    $targetObject,
                                    $targetMethod) {
        $sourceObject->__eventRegistry[$forEvent][] = array($targetObject,$targetMethod);
    }
}

This implementation should be session-save as well, as the dynamically built "__eventRegistry" should be serialized to and restored from the session automatically. For class based event registries this may be a little more tricky to implement.

But once the "strict" keywork is incorporated into PHP, this approach will not work on classes anymore that are marked strict.

Saturday, August 19, 2006

Enumerations in PHP

Sometimes you stumble over stuff on the net and really think to yourself. Wow! Why does not everybody talk about it yet? My Subject of the day is Enumerations in PHP via SPL_Types. Basically it brings Enumerations to PHP, ensuring that a variable may only contain specific values based on a value domain. This should be looking something like this.


class Weekday extends SplEnum
{
  const Sunnday = 0;
  const Monday = 1;
  const Tuesday = 2;
  const Wednesday = 3;
  const Thursday = 4;
  const Friday = 5;
  const Saturday = 6;
  const __default = Weekday::Sunday;
}

$e = new Weekday;

var_dump($e); // shows object of type SplEnum
var_dump((int)$e); // int(0)

$e++;

var_dump($e); // shows object of type SplEnum
var_dump((int)$e); // int(1)
var_dump($e + 3); // int(4)
I have found this example over at a mailing list transcript at BeebleX. While there is certainly a trace of this functionality in the CVS Repository at php.net you cannot yet get a precompiled version of the extension at PHP-Snaps :-(.

Personal note: While I love PHP for the fact that it's a dynamically typed language, I consider Enumerations a big help, to communicate and ensure consistency of parameter values on public interfaces.

Validating user input using PECL::filter

PECL::filter is a new promising PHP extension, which will come with the new PHP 5.2.0. It is mainly meant for validation of input, which currently requires quite some work. Since there is no documentation over at php.net you can read all about it over here. For all the guys using Windows for your development environment here you can download the compiled extension for your current PHP installment.

Thursday, August 10, 2006

Calculating distances

Since I seem to have a fav on geo-calculation since Google-Maps has hit me, I have been looking for some information how to calculate distances between to points on the globe.

The GoogleAPI actually has a method to calculate the distance between points based on a shperical model.

But what if you'd like to implement a radius search on the database or calculate distances on the backend. I found a nice introduction for the subject over at MeridianWorldData, which takes into account various levels of precision to gain performance, where it is needed.

Also I found a PHP based example for distance calculation as well as a series of articles on the subject of GIS mapping.

Mashup GoogleMaps and GeoIP

Ok I have put together a small example of how to use GoogleMaps and GeoIP. Use it to look up where a specific URL or server is hosted.

You can view it here. The application includes a bookmarklet, which you may bookmark or place in the link's bar of your browser to use it from every website to determine it's location.

For all you PHP freaks, you can download the complete example as well. Just unpack the ZIP file on your PHP5-enabled server and you should be good to go. Just make sure to use your own GoogleMaps API key, you can get here.

Republished CSTL

I have just republished the article and samples about CSTL (Client Side Tag Libs), which brings TagLibs to JavaScript in an extensible object oriented model. The original articles are well 1 1/2 year old but since everyone seems to talk about AJAX these days, I just want to show, that I had my 50cent to distribute to that subject a long time ago. Besides the links were not working in quite a while.

full article download files

Wednesday, August 09, 2006

Matching IP to country

I have again found a nice article about how to match IPs to countries over at builder.com. It uses PHP::Pear's Net_GeoIP class for the querying. But what really interest me is the data behind it. Luckily MaxMind does provide this data in various flavors.

There is a free CSV export at the beginning of every month, which can be downloaded on country level and on city level.

However there are also 2 APIs for PHP. For once there is a pure PHP implementation and also a PHP extension as well.

I am definately going to try these out!

Tuesday, August 08, 2006

Creating MS Office documents using PHP

I have recently discovered an article on how to generate MS Office Documents using PHP. Basically this article does not contain anything new, demonstrating how to utilize the COM API to construct Word and Powerpoint and how Excel can be created from an HTML table. While this article will not enable you to approach the issue in an OS independent way (you will in fact need a windows server to create Word and Powerpoint documents) it still assembles the concepts for all 3 major MS Office products, containing easy to understand code snippets.

24 ways to impress your friends

24 ways owns a collection of 24 very nice articles about bleeding edge JavaScript and CSS hacks to make things look good and work well. Definately worth a look or two if you are in the web business.