Archive for the 'web development' Category

Overview: Learning PHP Data Objects, by Dennis Popel, is an introduction to PDO, which walks through the building of a believable test example - a library manager for your home library. Each chapter introduces a new facet of PDO and shows how to rewrite the appropriate parts of the application to slot the new ideas in. Very clear and easy to read. Non-PDO subjects are appropriately kept to the appendices.

I really couldn’t find very much about this book that I didn’t like. Ignoring the appendices, the book is 154 pages purely devoted to teaching PDO through examples, including error handling, working with BLOBs, even the creation of the M in MVC (Models).

I mentioned MVC there. One of my gripes with most tutorials of MVC is that they introduce the concept simply, then provide pages and pages of code with the end product which is “hello world”. Why I should go to all that trouble instead of simply writing <php echo 'hello world'; ?> to the screen usually escapes me. Dennis, however, concentrates solely on the Model and shows exactly why it’s a great idea. I think some more separation of concerns would have been better (don’t mix Author and Book SQL in the same object, for example), but the ideas were all good.

I think that if Dennis was going to show how the Model works, he should also have gone a little further and showed an example of an Active Record pattern as well. But I guess the point of showing MVC was more to show /an/ example of abstraction of the DB code, and that was sufficient.

The book covers a Library manager application all the way through from conception to implementation, demonstrating at all points that the code works with SQLite and MySQL (and by implication, all other DBMS’s) with a change of only the connection string.

Possible problems are explained clearly and solutions are provided. For example, Dennis explains why, after you compile the query select * from books, PDO (and indeed the database itself) does not know how many rows it will return. A solution, in the form of a very smart getRowCount() function shows a query-agnostic method for counting results of an arbitrary line of SQL.

Other areas that are covered in the book include error-handling, prepared statements and transaction-handling.

PDO can handle Prepared Statements even if the underlying DBMS cannot handle it, so it is possible to write your code in a cross-platform way. Examples of why you should use this are provided. One of the examples shows an efficient way to handle insertion or updating of a table using the same parameters for both cases, with the row-handling function deciding whether to use update or insert based on whether an ID was provided.

I feel the Transactions section could have been expanded a bit further. It is not explained how PDO handles this for DBMS’s that don’t internally support transactions, and I wouldn’t like to assume that they work all the time, only to find after deleting critical data that it’s not supported.

Overall, I enjoyed reading this book. Dennis is a good writer and I think he explained his thoughts very clearly.

On an aside, my four-year-old son Jareth loves Packt Publishing’s books. Sometimes when I go to read another chapter, I need to covertly steal the book I’m reading back from him. For a while, he made it a bed-time ritual to grab all the Packt books he could find around and bring them up with him to read in bed. I think he loved the screen-shots and the frequent code samples. He’s high-functioning autistic and likes literary constructs, and programming books are perfect for him in that regard. Thanks Packt, you’ve made my son (and therefore me) happy.

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.

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)
  }
}