Posts tagged with 'php'

Use labelled groups in Regular Expressions for clearer code

I keep seeing this sort of pattern in PHP code, when people match on Regular Expressions:


$orderNumber = 'CLK-TEST001-030';
$pattern = '/([a-z]+)-([a-z]+([0-9]+))?-([0-9]+)/i';

if (preg_match($pattern , $orderNumber, $matches)) {
    echo "Prefix was ".$matches[1]." and duration was ".$matches[4];
} 

The problem here is that the numbers 4 and 1 are kind of cryptic. Furthermore if the expression changes in future I'll probably need to go through my code and redo the numbering.

A better alternative is to name the groups inside the expression:


$orderNumber = 'CLK-TEST001-030';
$pattern = '/(?<prefix>[a-z]+)-([a-z]+([0-9]+))?-(?<duration>[0-9]+)/i';

if (preg_match($pattern , $orderNumber, $matches)) {
    echo "Prefix was ".$matches['prefix'].
        " and duration was ".$matches['duration'];
} 

This way if the expression gets changed, I can still use the same named fields in my matches in the subsequent code.

Using partial mocks in PHPUnit to test tricky code

At work we've been going through the fairly painful process of adding unit tests to existing code. I'd like to share one technique I've found useful, a way of testing methods that at first glance look like they have too many dependencies to easily get under test.

I'll be giving these examples in PHPUnit but any xUnit framework should be able to do something similar.

Consider a method like the following, which is the sort of thing you might have trouble seeing how to test:


class MyClass
{
    public function getDataAndPublishRemotely()
    {
        $data = DataStore::getUnpublishedData();
        
        $service = new SoapClient($SOME_WSDL);
        $service->publish(preg_replace('/[^0-9a0z]+/', '', $data));
    }
} 

So this is doing some sort of DB call, then calling a SOAP service and publishing a cleaned-up version of the result. What makes this hard to test is the fact it's got two solid dependencies - a static call to some sort of DataStore layer and a direct instance of a SoapClient class.

Eventually the way to fix this sort of thing is to inject both of those dependencies separately, but that's too big a refactoring to tackle straight away. When you're modifying a class to get it under test you want to do small, easy-to-understand changes and get it under test ASAP.

One approach to getting it tested is to split the functionality that you think you can test into a separate method, like so:

Zend Framework bindings for Frontal

Having thought further about Frontal, Carl's JS library, I wrote a quick View Helper to make it easier to use it in Zend Framework projects.

It's available to download on Dropbox, it's available under the MIT licence. I'll bung it up on somewhere like GitHub once I work out how Git works.

Basic usage

Before you do anything you'll need to register the helpers in your application.ini:

Clarifying Javascript-PHP communication using JSON-RPC


( ! ) Warning: DOMDocument::loadHTML() [domdocument.loadhtml]: htmlParseStartTag: invalid element name in Entity, line: 1 in /var/www/ciaranmcnulty.com/application/models/Post.php on line 25
Call Stack
#TimeMemoryFunctionLocation
10.000266624{main}( )../index.php:0
20.03442985204Zend_Controller_Front->dispatch( )../index.php:47
30.04043466600Zend_Controller_Dispatcher_Standard->dispatch( )../Front.php:946
40.31808156472Zend_Controller_Action->dispatch( )../Standard.php:293
50.31808156608BlogController->tagAction( )../Action.php:502
60.33498169792Zend_Controller_Action->render( )../BlogController.php:204
70.33508169792Zend_Controller_Action_Helper_ViewRenderer->render( )../Action.php:207
80.33578169792Zend_Controller_Action_Helper_ViewRenderer->renderScript( )../ViewRenderer.php:942
90.33578169792Zend_View_Abstract->render( )../ViewRenderer.php:921
100.33588211060Zend_View->_run( )../Abstract.php:787
110.33618227224include( '/var/www/ciaranmcnulty.com/application/views/scripts/blog/list.phtml' )../View.php:107
120.35868254668Post->getSummary( )../list.phtml:13
130.35868254668DOMDocument->loadHTML( )../Post.php:25

( ! ) Warning: DOMDocument::loadHTML() [domdocument.loadhtml]: Unexpected end tag : pre in Entity, line: 58 in /var/www/ciaranmcnulty.com/application/models/Post.php on line 25
Call Stack
#TimeMemoryFunctionLocation
10.000266624{main}( )../index.php:0
20.03442985204Zend_Controller_Front->dispatch( )../index.php:47
30.04043466600Zend_Controller_Dispatcher_Standard->dispatch( )../Front.php:946
40.31808156472Zend_Controller_Action->dispatch( )../Standard.php:293
50.31808156608BlogController->tagAction( )../Action.php:502
60.33498169792Zend_Controller_Action->render( )../BlogController.php:204
70.33508169792Zend_Controller_Action_Helper_ViewRenderer->render( )../Action.php:207
80.33578169792Zend_Controller_Action_Helper_ViewRenderer->renderScript( )../ViewRenderer.php:942
90.33578169792Zend_View_Abstract->render( )../ViewRenderer.php:921
100.33588211060Zend_View->_run( )../Abstract.php:787
110.33618227224include( '/var/www/ciaranmcnulty.com/application/views/scripts/blog/list.phtml' )../View.php:107
120.35868254668Post->getSummary( )../list.phtml:13
130.35868254668DOMDocument->loadHTML( )../Post.php:25

( ! ) Warning: DOMDocument::loadHTML() [domdocument.loadhtml]: htmlParseStartTag: invalid element name in Entity, line: 86 in /var/www/ciaranmcnulty.com/application/models/Post.php on line 25
Call Stack
#TimeMemoryFunctionLocation
10.000266624{main}( )../index.php:0
20.03442985204Zend_Controller_Front->dispatch( )../index.php:47
30.04043466600Zend_Controller_Dispatcher_Standard->dispatch( )../Front.php:946
40.31808156472Zend_Controller_Action->dispatch( )../Standard.php:293
50.31808156608BlogController->tagAction( )../Action.php:502
60.33498169792Zend_Controller_Action->render( )../BlogController.php:204
70.33508169792Zend_Controller_Action_Helper_ViewRenderer->render( )../Action.php:207
80.33578169792Zend_Controller_Action_Helper_ViewRenderer->renderScript( )../ViewRenderer.php:942
90.33578169792Zend_View_Abstract->render( )../ViewRenderer.php:921
100.33588211060Zend_View->_run( )../Abstract.php:787
110.33618227224include( '/var/www/ciaranmcnulty.com/application/views/scripts/blog/list.phtml' )../View.php:107
120.35868254668Post->getSummary( )../list.phtml:13
130.35868254668DOMDocument->loadHTML( )../Post.php:25

I think of myself first and foremost as a PHP developer but serious sites are getting more and more JS-heavy as time goes on so it gets harder (and less pragmatic) to try and avoid dealing with JSPHP communication of some sort.

I'm a big advocate of RESTful design so tend to end up attempting to write scripts that do lots of GETs and POSTs (as appropriate) and parsing out whatever custom response format I've decided JSON requests will return. It feels good - like I'm sticking to my principles and 'doing it right' but it's a long painful slog that can feel like self-flagellation at times.

It's also slow and hard to prototype - it's hard to argue in favour of some abstract design idea when it's making you take forever to generate simple tasks . Sometimes when I feel lazy what I really want is a way of calling my PHP objects directly from the JS and not worrying about what's happening in the underlying HTTP, and that's what JSON-RPC provides.

In this blog I'll be showing some simple examples of JSON-RPC in action but first let's look at the pros and cons.

Why you should close PHP sessions as soon as you can

When serving files with PHP, you may notice a curious effect where only one request gets served at a time per user.

You can see it if you're the kind of retro throwback who uses framesets served via PHP - the panels will load in one at a time. You'll see the same thing if you generate a load of images via PHP - they'll pop up sequentially - and if you serve large video files via PHP like we do at work you may see a curious effect of the downloads queueing up. Those of you with AJAX applications may be victim to this without realising, but if you're serving JSON/XML responses from PHP scripts you'll find that your parallel AJAX requests will only get served one at a time.

I've seen this effect a few times and always ended up working around it. The odd thing is this isn't a setting in Apache or a global slowdown of your server. PHP just refuses to serve more than one request per user at a time. Luckily Kevin managed to spot the reason, and it was a new one on me even after 9+ years of using PHP (it's possible everyone else knows about it, mind you).

The answer is pretty simple: PHP can only handle one response at a time if you have an open session.

Doctrine article in php|architect

Ah, fame at last!

Cover of php|architect

The latest issue

It looks like the new issue of php|architect is out, and contains my article about Doctrine, the PHP-based Object Relational Mapper.

It feels like ages since I wrote it (I'm no longer a 'freelance PHP developer' for a start) so re-reading it was actually a slightly weird experience.

It's my first published work, and I'm fairly happy with it. Hopefully I'll get another chance to write for php|architect, I just need to think of another subject that I have something to say about.

The bad news for most of you cheapskates is that php|architect is a subscription-only publication so you can't read my article for free! However, I would genuinely recommend the magazine, especially as it's only effectively $2.50/issue. Obviously I wouldn't recommend it for people who aren't interested in PHP, however!

Using Twitter as a voting platform

Cast of Star Trek

Like a lot of other people, I've had a love/hate relationship with Twitter. At first I didn't see the point - it was just Facebook without the features, then I drank the kool-aid, and fell in love with its simplicity and openness. Nowadays I've backed off a bit and see it as an interesting social phenomenon that I enjoy being a part of. I'd been meaning to check out the Zend_Service_Twitter PHP library for a while, but hadn't really thought of an excuse.

A few weeks back I was unlucky enough to watch Star Trek V and tweeted about how crap it was, despite my friend Nick thinking it's the best of the lot. There was a bit of back and forth, so I posted an order for the films, from best to worst. A few of my friends then did the same, with the hashtag of #startrekrank as a way of identifying the posts.

It struck me that I could somehow aggregate these results using the Twitter API, so I present to you, StarTrekRank.com!

Simplify pagination logic using a custom Zend_Paginator_Adapter

Pagination logic is something that I've found myself redoing a number of times over the years, and each time it's been a relatively fiddly and painful process.

This time around I decided to check out the Zend_Paginator component from the Zend Framework, and found the process useful enough to share! In my case I was using Doctrine to retrieve data from the database. I'll skip most of the Doctrine-specific stuff, however, as hopefully this will end up as a decent example of how to integrate Paginator with other non-Zend libraries.

When the Paginator is instanced, it's given an instance of an appropriate Adapter and told what the current page is:

<?php
$paginator 
=  new Zend_Paginator($adapter);
$paginator->setItemCountPerPage(20);
$paginator->setCurrentPageNumber(2);

Article in php|architect (maybe)

Sorry for the lack of recent posts - I've been distracted recently working on an article I've written for php|architect.

In theory it'll be in the August issue but these things are subject to change and frankly they could probably still reject it if they wanted to.

Anyway there's still time to subscribe if you want to get a copy!

Simplifying file operations using PHP stream wrappers

When I took the Zend certification exam, one of the areas I really wasn't very clear on was PHP's stream wrappers. Since reading up on them for the exam, I've been kicking myself for not using them before, the amount of simplification they allow for common code is ridiculous.

As an example, a colleague recently showed me some code he'd written that downloaded a .dat.gz file from a remote server, saved it to disk, unzipped it and save the expanded contents into a file. The original code he showed me was similar to the following (with a lot more error checking and comments):

<?php 

$tempfile 
tempnam(sys_get_temp_dir());

// get the file from FTP to local disk
$fh ftp_connect('ftphost.com'21);
ftp_login($fh'username''password');
ftp_get($fh,$tempfile'/path/to/file.dat.gz');
ftp_close($fh);

// read data from local .gz into var
$gh gzopen($tempfile'r');
$data gzread($gh1000000);
gzclose($gh);
unlink($tempfile);

// write data to local .dat
file_put_contents('/local/copy/of/file.dat'$data);

The first thing to note is that the ftp functions have an underscore in, while the gz functions don't. To me at least, this makes it almost impossible to remember without constantly referring to the reference. The second thing to note is that by downloading the file to disk first, then reading it into memory, then writing it to disk, we're doing a three-step process.

Keeping querystrings clean with Zend Framework

I'm something of a zealot about short, readable URLs. Most people by now are using server rewrite rules and Front Controllers of some sort to keep the paths in their application sane and legible, but an area that's often overlooked is the querystring, especially after a form submission.

A typical example of a situation with a 'messy' querystring might be a search form on site. When a form is submitted, all the elements in the form are entered into the querystring whether they're relevant or not.

That leads to querystrings like /search?size=&shape=&colour=red&age=, which would be a lot more legible as /search?colour=red

On some sites I work with, an 'advanced search form' can have up to 20 elements, all of which might get submitted in one go leaving the search results page with a huge URL.

Delivering pages as PDF using PHP

HTML is great. It's the lingua franca of the web, and a fantastic format for exchange of hyperlinked information. However, it has its drawbacks - It typically relies on multiple external files, different browsers interpret it in different ways, and printing it is a bit of a minefield, even with the limited print CSS currently available.

So, sometimes it makes sense to present documents as a PDF as well. I've done so on this very site, with my CV, after finding that most recruitment sites won't except an HTML document, and recruiters just get confused when you attach one to an email (or send them a hyperlink).

The component I use is called dompdf. At its heart it is an HTML->PDF converter written completely in PHP, and is pretty simple to use. The code to convert some HTML to a PDF looks something like this:

<?php

// include in the dompdf library
require_once('dompdf_config.inc.php');
spl_autoload_register('DOMPDF_autoload');

// instance dompdf
$dompdf = new DomPDF();
$dompdf->set_paper('a4');

// tell the user-agent to expect a PDF
header('Content-type: application/pdf');

// load the HTML, convert it to PDF and output
$src file_get_contents('document.html');
$dompdf->load_html($src);
$dompdf->render();
echo 
$dompdf->output();

?>

Some thoughts on Zend PHP5 Certification

ZCE logo

I qualified as a ZCE yesterday. I guess the only tangible benefits of this is I get to write the letters on my CV / business cards and use this nifty logo, but I found the overall process of the certification pretty worthwhile.

The thing that's put me off certification in the past is the imagined cost, in terms of both time and money. I thought there'd be a dreary course covering things I already knew, and I'd be paying a premium for the privilege. In fact, I was completely wrong!

Once I looked into it, I found that although Zend offer a grueling 18-hour course for about £800 it's not a requirement for the certification itself, you can buy an exam voucher for about £100 and just turn up and take the test, so I did.

A new comments system

I've made a little comments system for this blog, and it gave me a chance to look a bit more into Doctrine.

I keep meaning to blog about how I put this site together, but for now I'll just say that it uses Zend Framework for MVC, with Doctrine for the ORM. To implement the comments form I used a great bit of code from CodeUtopia, written by Jani Hartikainen (a.k.a. 'zomg' on IRC) that ties together Doctrine objects and Zend_Form in quite a nice way.

I'm hoping to do a quite simple tutorial about how to implement a small blog, but that's for another time when I'm not busy revising for my ZCE!