PHP 5.3 was released today; here are my positive and negatives:
The Good: Closures
Anonymous functions created with create_function have always been a bit messy. With 5.3 comes support for closures with a much cleaner syntax:
$greet = function($name)
{
printf("Hello %s\r\n", $name);
};
$greet('World');
$greet('PHP');
The Bad: Backwards incompatible changes
Although not a massive change from 5.2, there are enough differences to break existing code.
The Ugly: Namespaces
There has been quite a discussion about PHP’s new namespace syntax.
$c = new \my\name\MyClass;
It’s just damn ugly. The more sensible choice, :: is already used as the scope resolution operator and was therefore dismissed.
Since the iPhone OS 3 update, you can now use the CalDAV protocol to automatically keep your Yahoo! Calendar updated on your iPhone:
Can I sync with my iPhone over the air?
Adding additional functionality to the standard Apple-supplied PHP on Mac OS X 10.5 is a little tricky if you are running a 64 bit processor such as the Intel Core 2 Duo. The reason is that any dynamic extensions that you add will need to be 64 bit, and many shared libraries by default with compile as 32 bit binaries. Trying to use a 32 bit extension with a 64 bit PHP results in the following unfriendly error message:
PHP Warning: PHP Startup: Unable to load dynamic library './mcrypt.so' - (null) in Unknown on line 0
mcrypt is a good example of a useful extension that can be added to PHP with a little bit of effort:
- Open up your Terminal.app
- To explicitly build for 64 bit architecture
export CFLAGS="-arch x86_64"
- Download libmcrypt from sourceforge http://sourceforge.net/projects/mcrypt
- Unpack the archive
cd libmcrypt
./configure --disable-shared
make
sudo make install
- download PHP 5.2.6 source from http://www.php.net/get/php-5.2.6.tar.bz2/from/a/mirror
- unpack the archive and go into the
php-5.2.6/ext/mcrypt/ dir
phpize
./configure
make
sudo make install
- verify the extension is 64 bit:
file /usr/lib/php/extensions/no-debug-non-zts-20060613/mcrypt.so
/usr/lib/php/extensions/no-debug-non-zts-20060613/mcrypt.so: Mach-O 64-bit bundle x86_64
To actually use the extension, you can simply create a symbolic link to it. For example:
cd ~/Sites
ln -s /usr/lib/php/extensions/no-debug-non-zts-20060613/mcrypt.so
Example code: mcrypt.php
Drop the following code into your ~/Sites directory to verify everything is working:
<?php
if ( ! extension_loaded('mcrypt') ) {
dl('mcrypt.so');
}
$key = "this is a secret key";
$input = "Let us meet at 9 o'clock at the secret place.";
$td = mcrypt_module_open('tripledes', '', 'ecb', '');
$iv = mcrypt_create_iv(mcrypt_enc_get_iv_size($td), MCRYPT_RAND);
mcrypt_generic_init($td, $key, $iv);
$encrypted_data = mcrypt_generic($td, $input);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
print_r($encrypted_data);
?>
Make sure PHP is reporting all errors and warnings.
Warnings and notices are PHP’s way of letting you know that you are utilising features in a non-standard way. If your code is omitting errors, then it should be fixed as soon as possible. Strict warnings are a class of errors that are turned off by default in most PHP installations. Turning on strict warnings gives you another level of error reporting, which is helpful to prevent you from using misusing functions, making sure your code is compatible with future PHP versions.
In the example here, using date() without explicitly setting a timezone will result in an E_STRICT warning. In this case, we are using a function called strictErrors to tell PHP to report all error types.
Example
<?php
function strictErrors() {
$reporting_level = E_ALL;
// if version of PHP < 6, explicity report E_STRICT
if ( version_compare( PHP_VERSION, '6.0.0', '<' ) ) {
$reporting_level = E_ALL | E_STRICT;
}
return error_reporting( $reporting_level );
}
// turn on strict error and warnings
strictErrors();
// produces strict warning
echo date( "d-M-Y" );
// no warning
date_default_timezone_set( 'Europe/London' );
echo date( "d-M-Y" );
?>
Further information
One of my issues with Perl has always been its implementation of OOP. Or, to be precise, the multitude of ways that a class can be declared (blessed hash, inside-out, Class::Std etc). I would argue that this is a case where TMTOWTDI is not advantageous. Enter Piers Cawley and his Moose for Ruby Programmers talk at the London.pm Technical Meeting, 20th February 2009. MooseX::Declare is yet another way, but check this out…
use MooseX::Declare;
class BankAccount {
has 'balance' => ( isa => 'Num', is => 'rw', default => 0 );
method deposit (Num $amount) {
$self->balance( $self->balance + $amount );
}
method withdraw (Num $amount) {
my $current_balance = $self->balance();
( $current_balance >= $amount )
|| confess "Account overdrawn";
$self->balance( $current_balance - $amount );
}
}
class CheckingAccount extends BankAccount {
has 'overdraft_account' => ( isa => 'BankAccount', is => 'rw' );
before withdraw (Num $amount) {
my $overdraft_amount = $amount - $self->balance();
if ( $self->overdraft_account && $overdraft_amount > 0 ) {
$self->overdraft_account->withdraw($overdraft_amount);
$self->deposit($overdraft_amount);
}
}
}
Firstly, yes, that is indeed Perl. Secondly, wow: it actually looks like a class definition. And this was the big win for me, as anyone coming from a Java or PHP background will find it trivial to understand what’s going on here. The main point is that by using MooseX::Declare, you are moving towards a more declarative programming style describing what the program should do rather than how it should achieve it. So, no more unrolling @_
Links
preg not ereg
This is the first in what I hope will be a regular series of posts on PHP best practices, inspired in part by Damian Conway’s Perl Best Practices book.
Historically, PHP has had two incompatible regular expression engines available, POSIX Extended and PCRE (Perl Compatible Regular Expressions). Arguably, Perl-compatible regular expressions are more powerful since they support non-greedy matching, assertions, conditional subpatterns and a number of other features not supported by POSIX Extended. More importantly, the POSIX Extended extension is deprecated as of PHP 5.3, meaning that a call to any of its functions, such as ereg, will emit a E_DEPRECATED notice. Therefore, for any regular expression functionality in your scripts, use the PCRE set of functions which are prefixed with preg_.
Example
$pattern = '/Hello/x';
$subject = 'Wake up and say Hello.';
$matches = array();
if ( preg_match( $pattern, $subject, $matches ) ) {
print_r( $matches );
}
Output:
Array ( [0] => Hello )
Further information
Introduction
This is a quick and dirty guide to the absolute minimum you need to get up and running with PhpDocumentor.
One of the slightly off-putting aspects of PhpDocumentor is the amount of tags (@) that are available, which can initially be overwhelming. e.g. see PEAR example:
PEAR sample file
This guide shows you the most important tags that you need to have in your documentation by means of an actual example: Accumulator.php.
Assumptions
- You are on a UNIX based machine, which includes Linux and Mac OS X.
- You are documenting object oriented rather than procedural code
Install
PhpDocumentor is part of PEAR. Install is easy:
sudo pear install phpdocumentor
Documenting your source code
The rules:
- One class per file
- One docbook block for the class, not for the file
- Filename is
<class name>.php
For the class:
- short description
- code example
@author
For each attribute:
For each method:
- short description
@param
@return
@see
Example class with documentation
Accumulator.php
<?php
/**
* An instance of this class represents a counting machine
*
* <code>
* require_once 'Accumulator.php';
*
* $acc = new Accumulator( 10 );
*
* $acc->addNum( 20 );
*
* echo $acc->getTotal();
* </code>
*
* @author Glen Scott <glen_scott@yahoo.co.uk>
*/
class Accumulator {
/**
* The running total
*
* @var int
*/
private $_number;
/**
* Create an instance, optionally setting a starting point
*
* @param int $initial an integer that represents the number
* to start counting from
* @access public
*/
public function __construct( $initial = 0 ) {
$this->_number = $initial;
}
/**
* Adds a number to the running total
*
* @param int an integer to add to the running total
*/
public function addNum( $num ) {
$this->_number += $num;
}
/**
* Returns the current total
*
* @return int returns the current running total
* @see Accumulator::$number
*/
public function getTotal() {
return $this->_number;
}
}
Creating your documentation
phpdoc --filename Accumulator.php --target docs
The "docs" directory is created and some HTML files are generated. Load docs/index.html into your browser to read your documentation.

Possible issues
"phpdoc: command not found". This means that the documentation generator script is not in your path. Run "pear config-get bin_dir" and add this directory to your shell’s $PATH environment variable.
Links
PhpDocumentor
When I sign up for new websites and services, I don’t want to give away my primary e-mail address so I typically set up a disposable address through SpamGourmet or AddressGuard. My thinking is that if a website then decides to spam me, I can just throw away the address and everything is hunky dory.
I’ve not had spam sent to any of my disposable addresses…. until today! So, which horrible site has decided to pass my e-mail address onto spammers? Step forward, Sega! I signed up for their Sega Pass site a few months back, for reasons that I now forget. And now they decide to send me this “Limited Time” offer:

Grrr.
Anyway, you know where you can stick your luxury units, Mr. Sega.
EnterpriseDB have kindly created a one-click installer for PostgreSQL, but unfortunately it doesn’t work out-of-the-box, at least not on my MacBook Pro. The problem is down to the amount of shared memory that is configured in OS X; by default it is 4Mb, and PostgreSQL requires 32Mb:

The error message suggests looking at the README file, which actually doesn’t exist. Luckily, there’s a simple fix; to increase the shared memory to the required 32Mb, create or edit the /etc/sysctl.conf file and include the following lines:
kern.sysv.shmall=8192
kern.sysv.shmseg=64
kern.sysv.shmmni=256
kern.sysv.shmmin=1
kern.sysv.shmmax=33554432
Reboot your machine for the settings to take effect, and re-launch the PostgreSQL installer which should now work as normal.