Feb 282012
 

Timezone handling can sometimes be a bitch. Turns out, using a couple of PHPs classes and functions, it’s quite easy.

Let’s say you have a web application with the following scenario:
Users from around the planet, and your server is located in the UK.

You would initialize your DateTime object like this:

$timezoneUTC = new DateTimeZone('UTC');
$dateTime = new DateTime('2012-02-23 10:22', $timezoneUTC);

echo $dateTime->format('Y-m-d H:i e').'<br/>';

This should output:
2012-02-23 10:22 UTC

For an international user, seeing his or her local time would be nice.
To do this, simply change the timezone of the existing DateTime object, like this:

$timeZoneSweden = new DateTimeZone('Europe/Stockholm');
$dateTime->setTimeZone($timeZoneSweden);
echo $dateTime->format('Y-m-d H:i e').'<br/>';

$timeZoneNY = new DateTimeZone('America/New_York');
$dateTime->setTimeZone($timeZoneNY);
echo $dateTime->format('Y-m-d H:i e').'<br/>';

$timeZoneBKK = new DateTimeZone('Asia/Bangkok');
$dateTime->setTimeZone($timeZoneBKK);
echo $dateTime->format('Y-m-d H:i e').'<br/>';

This should output:
2012-02-23 11:22 Europe/Stockholm
2012-02-23 05:22 America/New_York
2012-02-23 17:22 Asia/Bangkok

The final code should look something like this:

$timezoneUTC = new DateTimeZone('UTC');
$timeZoneSweden = new DateTimeZone('Europe/Stockholm');
$dateTime = new DateTime('2012-02-23 10:22', $timezoneUTC);
$dateTime->setTimeZone($timeZoneSweden);

This will leave a DateTime object set with the users timezone.

And that’s it.

Nov 012011
 

When you need to see if any of the chars in $chars is in another string.. Whats the simplest way to search for them?
Hopefully none of the libraries have such functionality, so you need to go “a bit lower”.
The answer is, ofcourse, trivial:

$chars = "xy";
$string = "the quick brown fox jumps over the lazy dog";

$found = false;
for($l = 0; $l < strlen($chars); $l++) {
        if (strpos($string, $chars[$l]) !== false) {
                $found = true;
                break;
        }
}
if ($found) {
        /* Do stuff */
}

But hang on. This feels a bit weird. Surely PHP must have a better way of doing this?
Browsing through the string section in the PHP manual you’ll notice PHP has bucketloads of native string functions. If you have a background from other languages, you could even just try and see if PHP has a function of the same name (which quite often it does) that solves the problem.

And sure enough, it does: strpbrk!

$chars = "xy";
$string = "the quick brown fox jumps over the lazy dog";
if (strpbrk($string, $chars)) {
        /* do stuff */
}

Just give the “problem” a second thought before going crazy with your coding, and keep in mind you aren’t just working with Symfony, Drupal, SugarCRM, WordPress, … Your good old pal, PHP, is there too.

Sep 092011
 

You would be forgiven for thinking that experts never do the boring beginners stuff. Surely, the football player getting paid X fantazillion gold dubloons a week (yes it is a figure so large it is measured by the week), surely he with all that skill and money, does not practise passing? Or ball receiving? But he does – in fact that is why he is an expert.

We are all in different places on our way to glory, stardom and general PHP-related insight – but what we have in common on this path could be that we have to keep practising the fundamentals. It is never a bad idea to re-read that man page, or to get more background information on things you already know. Since last time you visited that man page, you have learned new stuff which will give you more insight or a different perspective this time around. Often I find I have misunderstood some concepts, and repetition helps correcting a point of view about to go askew.

Here is a small example to get you started: did you know break[1] accepts parameters? Neither did I. Think about it. Why would you even look up break, you have used break hundreds of times before, you know how it works and when you should use it. In fact it is so basic you would think it does not have much of an entry – a quick lookup from vim in the PHP-docs [2] though – and tada – there it is. White on black: break accepts an optional parameter to break out of zero, one or more loop-flavour or switch. You know you will be needing it shortly.

Like that football player spending a late practise shooting at the goal, so should we practise our  fundamentals. I’m passing this on to bjori next month – he’ll give you one of his to ponder.

[1]   http://php.net/break
[2] You can have unix man pages for PHP functions integrated in Vim – so you don’t even have to waste bandwidth. Awesome. http://bjori.blogspot.com/2010/01/unix-manual-pages-for-php-functions.html

Apr 142009
 

I was working on one of my php free software projects this weekend, and found an interesting bug on one of my pages, resulting in a massive number of database lookups (203 for one page) where ~180 of them was the same “kind” of lookup. Investigating further, I found out that one of my functions which was using isset() was returning a different result than what I would’ve expected.

PHP isset()  has (to me) a very strange behaviour – not only does it check to see if your variable is set (defined), it also wants it to have a specific value. Or, not so much a specific value, but it doesn’t want it to be null. Which means that running:

echo isset($variable) ? ‘yes’ : ‘no’;
$variable = null;
echo isset($variable) ? ‘yes’ : ‘no’;
$variable = ‘anything’;
echo isset($variable) ? ‘yes’ : ‘no’;

will return “no” in the two first cases, while “yes” only on the third attempt.

This is apparently intended behaviour, according to php.net/isset:

Determine whether a variable is set.
If a variable has been unset with unset(), it will no longer be set. isset() will return FALSE if testing a variable that has been set to NULL.

In my case, I was maintaining a $settings array with keys that matched the setting. Instead of loading all settings at startup, I would load the general settings, and only load the user-specific settings on demand. This meant that I would populate the array with keys for the settings that were loaded, as they were loaded. If the key didn’t exist, it would need to look it up from the database. However, a setting can of course be null – in this case that just means that it is not specified for that user (or the general setting was null).

To determine whether a setting was loaded, I then used

if (!isset($settings[$key]))
{
$settings[$key] = doLookupSettingFromDatabase($key);
}

and then return the corresponding setting. This of course works whenever the setting is loaded – unless the setting is null. However, in this case, the array key was actually set – and the value of the key was set, just set to null. The isset() call in this case is a major fail.

In this setting it was a “simple” matter of replacing the isset()-call in the if-test with an array_key_exists()-call, which made the whole thing work as intended. You might also argue the case that I shouldn’t be using isset() in this case, and that array_key_exists() would be the intended function call (as the php docs suggests), but I don’t think that is correct.

I actually like to initialise variables that are later to be used, by assigning them an initial null value – and then if I want to see if I’ve set it to something meaningful, simply call

$variable = null;

{ … snippet of code that might change $variable … }

if ($variable !== null)
{
doSomething();
}

This has worked perfectly for me. I suspect the current isset() behaviour was implemented by someone that thought it was a great idea to implement the same logic in the isset() function. However – there are several situations where a variable would be assigned a null value, and calling isset() on that variable would then return false. In my opinion, a variable is only not isset() if unset() has been called on it. In all other cases, it is set, even if it is set to a null value.

There is of course no fix for this intended behaviour – as changing this isset() behaviour would cause a complete backwards compatibility break – so watch out for those isset() statements.

PS: This flawed logic is not applied to property_exists(). AFAIK, there is no “variable_exists” – this is what isset() is for, and the documentation for property_exists() actually mentions this. Fail x 2, but props for pointing it out in the manual.

PS2: This would probably be a good case to argue the undef data type.