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.

Sunday, July 30, 2006

Playing nicely with Search Engines

The subject may be as old as the web itself but still today, one tool to market your website is to have it have a high ranking with search engines. The Ultimate SEO Checklist seems to be a comprehensive article on this subject. It does not compile all the new ideas into a single article but also presents some new techniques.

I like the style of this article since it presents facts rather than "shoulds" and "mays".

Saturday, July 29, 2006

Google Code - APIs and more

The recent hype for mashup-applications has certainly fueled the run on the it's AJAX Maps API. But there are plenty other APIs, which google offers, also worth a look. What will be certainly interesting for me, will be the Blogger Atom API which you can use to search and modify your blogs on www.blogger.com.

Also Google now hosts your open source projects, similar to the sourceforge.net way.

PHP Sockets Made Easy

There is a really nice tutorial up about creating and consuming sockets usiung PHP. At the time of this writing the first part of a 5 part tutorial series is published. I am going to following it, since I have recently written a generic Socket-Server and want to see things, I may improve.

Tuesday, July 18, 2006

Adobe - Reader Download

What the hell is this? I am trying to upgrade my quite old instance of acrobat reader 5 since some new documents seem to require it. But this seems to be not quite such an easy task.

On the download-page for the adobe reader I am getting a EXE-file which tries to execute an AOM file, which of course I have no runtime for. If I retry downloading, the AOM file hops directly into my face. Since I am not willing to get me yet another installer for an installer, I guess I'll stay on acrobat 5 for awhile.

Way to go guys! This certainly spreads adobe reader faster ;-)

dompdf - The PHP 5 HTML to PDF Converter

Finally there seem to be a decent API for PHP developers to render HTML to PDF. I have just downloaded and unpacked domPdf on my WAMP and it worked right away.

Ok I had to disable php_domxml.dll first but after that it worked perfectly. Well almost, since there seems to be a problem with special characters. I guess I need to import some additional forms first before this works correctly.

Anyhow this API is a big step forward for PHP developers trying to find an easy and convenient way to create PDFs from what they know best: PHP and HTML.

Saturday, July 15, 2006

Download SYSCON's Magazines

Browsing some old Links of mine and modifying some URLs. I got access to the public PDF download area of SysCon, who have brought to you e.g. the MXDJ (Macromedia Developer Journal, which all of it's issues may be downloaded here). I liked reading the magazine in the past and might continue now...

Sunday, July 09, 2006

2Advanced Studios

2Advanced Studios have released their new site called "v5 Attractor". Again its a very impressive experience graphical-wise and certainly worth a look if you like surfing the web just for enjoyment and to see what Flash can do.

Patterns For PHP - WebSites

Since PHP-Patterns does not seem to get any new content for quite awhile (probably because Harry Fuechs has moved his activities over to Sitepoint), the new Patterns For PHP website seems to take the same approach of an open wiki on the subjects of design patterns for PHP.

Hopefully this time there will be a longer lasting effort on the subject since I personally like pattern-pages very much. For all those of you that are craving patterns on an abstract non-implementational level Martin Fowler's website might be worth a look.