review: Object-Oriented Programming in PHP5

by Hasin Hayder, Packt Publishing

In short: a very good concise introduction to OOP. I’ll be keeping this on my desk for a while. The language use is strange but the code examples and the spread of topics make up for that in spades. This book has a very broad scope, but is clear in the essentials. If you’re looking for an introduction to Objected Oriented Programming in PHP, I’d recommend this one.

The Good

The book does a good job of introducing PHP objects. I’ve done OOP in C++, Java and PHP, and found Hasin’s descriptions easy to read.

I liked that code examples are provided for almost every discussed idea. In fact, in some cases I found that the code was so readable it explained things that were not stated in the surrounding paragraphs.

I’ve been coding in PHP since the 90s and avoided doing a lot of OOP because I was aware that it was not widely available until PHP5 came out. Only recently, the GoPHP5 project started pushing for the adoption of PHP 5.2 as a minimum. As a result of that, I’ve started assuming a base level of 5.2 in my own work, and that allowed me to work properly with objects.

This book, then, is a good reference to keep on my table as I update my own coding style.

It has a clear discussion of PHP’s handling of objects, with details on probably all aspects of it – Hasin certainly knows more about OOP in PHP than I do, so I can’t find any faults!

Following the description and examples of Objects in PHP5, the book then moves onto Patterns, providing a short description of the major patterns. Good programmers will already be aware of these, but it is always good to have a reminder.

I’ve never done Unit Testing (yes, bad me – I’m a fan of Selenium, though), so the chapter on Reflection And Unit Testing was perfect timing for me – I’ve been pressuring myself recently to get into unit testing, and this was the perfect way to start. A quick overview of how to unit-test objects was provided. I had a few questions at the end of the chapter, but they’re probably best left for a book specifically on unit testing.

The SPL chapter was a little surprise for me. I wasn’t aware of these classes in PHP5. Although, considering my knowledge is bassed mostly on Procedural Programming and the PHP.net manual, which is mostly Procedural, this is not surprising. The book described some objects such as RecursiveDirectoryIterator and SPLFileInfo which I found immediate application for in my own work.

There is also a chapter on MVC. I’m not really into MVC, so was interested to see if he could convince me that it was better than the methods I currently use, but no, I’m still not convinced.

The Bad

There are a number of stated assumptions in the book. For example, OOP is implicitly better than all other methods of programming. On page 12 of the book, a number of “benefits of OOP” are noted. Each of those benefits can apply to Procedural Programming as well. Not enough thought went into convincing the reader that OOP is better. I agree that OOP is better, but the arguments written in the book are not strong enough.

There are other assumptions in the book – that MD5-hashing a password is “the best” way of storing a password, that coders should never code from scratch as almost everything as already been written (he then goes on to write an MVC implementation from scratch…). Each of these assumptions detracts slightly from the readability of the book because it makes the book read as a personal opinion instead of an objective discussion.

Also, I didn’t like the frequent references to PHP4. let’s forget the past and concentrate on 5. The book is written for PHP5, so there should be minimal discussion of PHP4 in it. Funnily, on page 13, this line appears: “In PHP5, objects are a lot more different than an object in PHP4. We will not discuss the details of this”. Two pages later, we have the sub-chapter heading “Difference of OOP in PHP4 and PHP5”. Some people may disagree with me, but I think that should be left to an appendix – the author should assume that the reader is coming to the subject with no knowledge at all. Describing old and new behaviour is confusing. Stick to the new.

I feel that a chapter should have been written which describes the conversion of an existing script from Procedural to OO. While it’s not difficult to do, it would have helped to explain the thoughts behind OOP.

The Ugly

The code samples were not readable enough, in my opinion. There were commented-out lines of code which should have been removed before publishing, and the indentation was non-standard and inconsistent.

The language used is difficult to read. I understand that Hasin is from Bangladesh and that English is probably not his first language, but as this book is written with an English-speaking reader in mind, the language should have been read over and corrected where it was non-standard.

Near the beginning of the book, Hasin lists off a short list of coding conventions to use. Throughout the book he then breaks most of them in his code. Granted, this doesn’t affect the /correctness/ of the code, but it is distracting when noticed.

The Table Of Contents doesn’t match the book! If you are looking for something using the TOC, then you need to add 4 to the page number it mentions. The Index is even worse, in that the page numbers are off /on average/ by about 3 pages.

It might come across from these comments that I didn’t like the book, but that’s not true – I enjoyed reading it and learned quite a bit from it. No review is complete, though, without some criticisms, and I just happen to be good at criticising.

I will re-read bits of the book over the next few weeks, and would recommend it to anyone that’s starting out in OOP in PHP.

monty hall – how it works

I was lying in bed last night, wondering how the Monty Hall trick works, and finally figured it out by twisting around my perception of the problem.

What is the Monty Hall problem? Consider three doors. Behind one is a car, and behind two others are goats. You are asked to choose one door – if it’s the one with the car, you win. otherwise, you lose.

you choose one car. Then Monty (the gameshow host) opens one of the other doors to show a goat behind it. You are given the chance to change your choice of door to the other closed one – should you?

The answer is Yes. the /intuitive/ answer is that there is a 50% chance either way, but mathematically, there is actually a 66% chance.

Took me a good few minutes to figure out how to verify it. I kept thinking of it as “there is a 33% chance of me picking the right one. door opens. I now have… 50%?”. Couldn’t seem to make the leap for some reason.

That was a result of wrong perception – you need to think of it from the point of view of what is /not/ the right door.

  1. choose one door. the chance of the car being behind one of the other doors is 66%.
  2. one of the other doors opens. the chance is still 66%!.
  3. You now have two closed doors. the door you /did not originally choose/ has a higher chance than the one you did choose, so you should switch.

efficient JS minification using PHP

Here’s a method to create minified JS files on-the-fly, without incurring the time cost of the minification process.

To explain, minification is the act of removing all whitespace from JavaScript so the file can be downloaded and parsed as quickly as possible.

A useful part of minification is that during the act of compiling your minified source, you can also pull in other JavaScript files and compiled them all into one single source. This has a major advantage that there is only one file to download. This is very important because even if those small files were small, the lag involved in sending multiple HTTP requests can sometimes be worse than if a single file which was twice the size of all the small files in total was downloaded. (which is why good web devs use Sprites when possible)

Right. That’s the explanation of /why/ to do it. Now how?

First off, here’s a very simple piece of source to show it (in a file called “all.php”).

  $js=file_get_contents('jquery-1.2.3.min.js');
  $js.=file_get_contents('jquery.dimensions.pack.js');
  $js.=file_get_contents('jquery.impromptu.js');
  $js.=file_get_contents('jquery.iutil.pack.js');
  $js.=file_get_contents('jquery.idrag.js');
  $js.=file_get_contents('jquery.grid.columnSizing.js');
  $js.=file_get_contents('jquery.tablesorter.js');
  require 'jsmin-1.1.1.php';
  $js=JSMin::minify($js);
  echo $js;

You can get jsmin-php from here. the other files are JQuery files but only used for illustrative purposes.

Anyone spot the problem? It does the job, yes, but the minify() script takes a few seconds to run, ruining the advantage it created with the minification.

The next step towards perfection is to cache the file. The obvious solution to that is to save the file in a location. If the file exists when the files are requested next, then serve the cached version instead of going through the minification process.

That’s not good enough, though. What if a file in the list was changed? You’d never know because the cached file will always be served.

The solution is to save the cached file in a file named using an MD5 of the last modified datetimes (genius idea – I’d love to shake the author’s hand). That way the cache will always be correct, and will automatically update itself when a file is changed.

$writabledir='/path/to/caches/';

function md5_of_dir($folder) {
  $dircontent = scandir($folder);
  $ret='';
  foreach($dircontent as $filename) {
    if ($filename != '.' && $filename != '..') {
      if (filemtime($folder.$filename) === false) return false;
      $ret.=date("YmdHis", filemtime($folder.$filename)).$filename;
    }
  }
  return md5($ret);
}

$name=md5_of_dir('./');
if(file_exists($writabledir.$name))readfile($writabledir.$name);
else{
  $js=file_get_contents('jquery-1.2.3.min.js');
  $js.=file_get_contents('jquery.dimensions.pack.js');
  $js.=file_get_contents('jquery.impromptu.js');
  $js.=file_get_contents('jquery.iutil.pack.js');
  $js.=file_get_contents('jquery.idrag.js');
  $js.=file_get_contents('jquery.grid.columnSizing.js');
  $js.=file_get_contents('jquery.tablesorter.js');
  require 'jsmin-1.1.1.php';
  $js=JSMin::minify($js);
  file_put_contents($writabledir.$name,$js);
  echo $js;
}

Better. This time, the delay is only on the first load. All subsequent loads will have an instant download of the cached file.

However, if you’re a developer, then almost every reload will involve the minification process – you’d never get your work done.

A solution is to check to see if the current MD5 cache exists, and if it doesn’t, then download the files as a bundle without minifying them. Instead, before sending the files, you tag on a little bit of javascript which will do the minification in the background after the script has been sent to the client.

Here is a complete solution, along with a little cleanup which removes caches older than an hour.

$writabledir='/path/to/caches/';

function delete_old_md5s($folder) {
  $olddate=time()-3600;
  $dircontent = scandir($folder);
  foreach($dircontent as $filename) {
    if (strlen($filename)==32 && filemtime($folder.$filename) && filemtime($folder.$filename)<$olddate) unlink($folder.$filename);
  }
}

function md5_of_dir($folder) {
  $dircontent = scandir($folder);
  $ret='';
  foreach($dircontent as $filename) {
    if ($filename != '.' && $filename != '..') {
      if (filemtime($folder.$filename) === false) return false;
      $ret.=date("YmdHis", filemtime($folder.$filename)).$filename;
    }
  }
  return md5($ret);
}

header('Content-type: text/javascript');
header('Expires: '.gmdate("D, d M Y H:i:s", time() + 3600*24*365).' GMT');

$name=md5_of_dir('./');
if(file_exists($writabledir.$name))readfile($writabledir.$name);
else{
  $js=file_get_contents('jquery-1.2.3.min.js');
  $js.=file_get_contents('jquery.dimensions.pack.js');
  $js.=file_get_contents('jquery.impromptu.js');
  $js.=file_get_contents('jquery.iutil.pack.js');
  $js.=file_get_contents('jquery.idrag.js');
  $js.=file_get_contents('jquery.grid.columnSizing.js');
  $js.=file_get_contents('jquery.tablesorter.js');
  if(isset($_REQUEST['minify'])){
    require 'jsmin-1.1.1.php';
    $js=JSMin::minify($js);
    file_put_contents($writabledir.$name,$js);
    delete_old_md5s($writabledir);
    exit;
  }
  else{
    $js.="setTimeout(function(){var a=document.createElement('img');a.src='all.php?minify=1';a.style.display='none';document.body.appendChild(a);},5000);";
  }
  echo $js;

A pseudo-code version of the above would be:

if file named after md5 of scripts directory exists, echo it and exit.
else{
  concatenate requested scripts into one large string.
  if request URI does not have "minify" as a parameter{
    add a javascript instruction to the string to load this script again with the minify parameter in 5 seconds
    print the string and exit.
  }
  else{
    minify the string.
    save the string to a file named after the MD5
    exit without printing anything (no reason to send this to the client)
  }
}

NIN, The_Slip

NIN - The Slip

Fresh from the success of their recent release, Ghosts, which Bronwyn has been playing non-stop since our CD arrived (and for weeks before using the MP3s downloaded from the Interweb), Nine Inch Nails has released a new album and gone even further.

Yes, this album is totally free for you to download. All they ask is that you sign up for it via their site. However, as the album is licensed via Creative Commons Non-Commercial, it is also legal for you to download via bittorrent if you prefer.

The album is available in MP3, M4A, FLAC and even 24/96 WAV (for freaks that want a 1.2GB album taking up space).

NIN are recommending that people take the album and produce remixes from it. (That site doesn’t work well in Firefox in Linux btw – fix it, please – remember I bought a ticket for your concert in the RDS way back in ’96? Go on Trent, be a pal!)

As for the sound, I think it’s more accessible than Year Zero (although I think over time, I will prefer Year Zero) on a first listen. There is the usual layered approach to the music, where textured “landscapes” are drawn up. Interestingly, in some tracks, the layers appear to be deliberately off-time from each other (Echoplex, for example).

nvidia in Fedora 9

…doesn’t work properly (at least on my laptop, using a GeForce 7000M). the reason for this is that Fedora 9 uses the latest version of xorg and NVidia‘s driver does not yet work with it (3D is not fully working).

To get stuff at least minimally working, you need to downgrade your xorg RPMs to the Fedora 8 versions.

Unfortunately, KDE4 appears to require fully working GLX in order to display the kicker (or whatever the hell they’re calling it now), so my KDE is slightly crippled at the moment. A pity, really, as KDE4 is beautiful and almost as usable as 3.5 was.