Latest Articles

Fabien Potencier: PHP does need a template engine

{ No Comment }

Fabien Potencier's latest blog post is yet another entry in the popular debate in the PHP community over templating. Recently, conventional wisdom has swung back to the use of PHP itself for templating, rather than one of the popular but resource intensive template engines like Smarty.

I discussed this myself here. At the time Brian Lozier wrote his article, his approach was probably in the minority. Other than the use of short tags, however, PHP for templating has seen a renaissance.

Fabien's angle on this, however, is anti-popular sentiment. He argues that PHP is too verbose to be a good template language, its syntax is not concise enough for templating, and it lacks sufficient reusability in a template context. I find the first two of these positions pretty subjective, and you'll find from the blog comments there are plenty of opposing opinions on this.

I posted my own comments over there, and re-print them here for your consideration. I think I made some valid points, but then again I have no perspective but my own, so I could be way off.

I've been templating directly with PHP for some time now using Brian Lozier's. I've since ditched the short tags, but for me, working in a solo environment, I'd rather have simplicity (don't have to learn a template engine syntax), control, and save the performance to spend later on things like actual application features.

Further, I'm not sure what all the heartburn over escaping variables in the template is about? IMO you should never be doing real work in the template anyway, any variables should be prepared in your controller class/script BEFORE being sent to the template. You're violating your own rule of separation of concerns by doing that much PHP work in the template. Likewise, making a function call in the template would violate the same principle. I've yet to encounter anything in two large scale enterprise apps that I couldn't template with PHP.

I also agree with the comments above that its not going to hurt the designer to learn a bit of PHP. Its really not that hard and it is a translatable skill. The en-vogue template engine of the day may or may not be in use in 5 years, but PHP will be.

I would argue that a very small percentage of total PHP developers are working in an environment where there is a separate templater that ONLY does the template work and has no knowledge of or role in application coding.

In the end, Fabien announces he's built upon some prior work by another developer to create yet another "magic bullet" template language. I had to re-think the intent of the article in its entirety once I realized at least part of his motivation must be to encourage folks to try out his new template engine. I do not fault Fabien for this (we all want to promote and share our work), but it causes me to reach the conclusion that his critique of PHP for templating is perhaps not 100% impartial.

Update: Eli White has also posted a response to Fabien.

Update 2: Padriac Brady has now posted a rather brutal response to Fabien:

Fabien's article triggered the urge once again to challenge the status quo, the continued view of something in PHP being necessary when in truth it simply isn't. The article takes that view to extremes, going to some effort arguing against the recent slide towards templating with PHP with arguments which are so biased as to misinform readers. [trackback]

And, now Fabien has posted a follow up to his original post:

Before I try to answer some questions, I'd like to reinstate that I like PHP templates. And you should remember that symfony has only used plain old PHP templates since the beginning. As a matter of fact, I'm been advocating about using PHP templates since my first PHP project, and I have never used any other PHP template engines. So, I'm not against PHP templates; I just find that some PHP limitations as a template language are more and more irritating for me.

Basic AJAX with PHP and jQuery

{ 4 Comments }

I gave a live tutorial/demo at work today for room full of folks. I've posted the source code and powerpoint below. The title is pretty self explanatory...just a very simple demonstration of AJAX techniques using jQuery JavaScript and PHP on the server side in a very crude Twitter-like mini-posting app.

Basic AJAX with PHP and jQuery - Source Code

Powerpoint Presentation

The problem with Database Abstraction Layers…

{ 8 Comments }

Let me preface this post by saying I reserve the right to be entirely mistaken, and I invite comments with opposing opinions...hey, maybe I'll learn something by mouthing off! I know I'm painting with very broad brush-strokes and I expect to be corrected where my statements may be overly generalized.

Now, as to the topic at hand:  The problem with DALs, PDOs, ORMs, data access objects, etc. (such as Propel) is that they are only "clean" solutions for relatively simple, single table queries and/or small result sets.

Larger databases will see huge hits on performance if you try to return only primary keys for a result set, and then loop through the keys, creating an object for each (thereby firing a query for each). For displaying result sets, a single query is vastly superior.

Further, the DAL pattern appears to break down when your query includes multiple joins and aliases. Properly normalized relational databases require joins in order to return relevant data about a record to the user, i.e. you don't store the user's full name in every sales order record, only the id reference to his record in the customer table. I've yet to see a DAL that can effectively deal with multiple joins and aliasing without asking the coder to write explicit SQL.

Let's look at an example of a "simple" query to demonstrate the power of DALs.  Here's the standard way to write a simple MySQL query with PHP.

$sql = "SELECT name FROM users WHERE id = '100' LIMIT 1 ";
 
$result = mysql_query($sql);
 
$row = mysql_fetch_object($result);
 
$name = $row->name;

Now, lets see how a theoretical DAL class might handle the same query:

$name = $db->Fetch_Var('users', 'name', 'id', '100');

Wow.  You can see what took us four lines of code before now takes only one.  The second example uses an actual method I've written for a simple DAL class I use at work.  If I can ever get permission from the licensing dept, I'll share it here.

For retrieving a single result or even an entire row (or rows) from a single table, such DALs can be effective and incredible powerful. However, for large scale paged result sets requiring joins, etc, I find it is most efficient to write custom SQL. In my opinion, these DALs are wishful thinking if the goal is to remove the need for the PHP developer to be able to write effective SQL. These tools should, rather, be treated exactly as such. Each is a tool to speed your coding and abstract away routine query building. But for any complex application, you are never going to get fully away from writing your own SQL queries. And due to the nature of these DALs/ORMs, the only SQL queries left to write are always going to be the most complex.

Propel actually does manage to provide some support for joins. I do not like Propel's reliance on the "*" wildcard in the linked example, but perhaps that is just for simplicity in the documentation. Good SQL explicity names the columns to retrieve, and except for in-development testing, you should rarely if ever use "*" ...its lazy coding and wastes resources (see Rudy Limeback's Simply SQL for a more detailed argument against "*"). I'd like to see Propel, or any other ORM/DAL class deal, however, with a query such as this:

SELECT SQL_CALC_FOUND_ROWS
          projects.id
          , faculty
          , author
          , author2
          , author3
          , date_created
          , users.last_name     as faculty_last
          , users.first_name    as faculty_first
          , users2.last_name    as author_last
          , users2.first_name    as author_first
          , dept.dept_name
          , project_title
          , project_type
          , staff_no
          , project_status
          , organization.org_name
          , project_date
FROM projects
LEFT OUTER JOIN users as faculty  ON projects.faculty = users.id
LEFT OUTER JOIN users as users2  ON projects.author = users2.id
LEFT OUTER JOIN dept ON projects.dept = dept.id
LEFT OUTER JOIN organization ON project.org = organization.id
LEFT OUTER JOIN staff ON project.staff_no = staff.id
WHERE (users.last_name LIKE '%smith%' OR users.first_name LIKE '%smith%')
AND project.title LIKE '%Material Composition of Unobtanium%'
ORDER BY Items.Entry_Date DESC 
LIMIT 0, 15

The above example is a sanitized (names anonymized to protect the innocent) version of a real query I use to return paginated results in one of our web apps. Some of the joins are included dynamically based on search criteria, others are always included. The WHERE clause is likewise generated dynamically, as well as the ORDER BY, which is used for column-based sorting.

Show me a DAL/ORM class that can deal with this example and I'll be your best friend forever.

Let's now look, for example, at Propel's approach to a multi-join query, taken from the above link.

Here's the standard SQL way:

SELECT * 
FROM author 
  INNER JOIN book ON book.author_id = author.id 
  INNER JOIN publisher ON publisher.id = book.publisher_id
WHERE publisher.name = 'Some Name'

Here's the Propel way:

$c = new Criteria(AuthorPeer::DATABASE_NAME);
 
$c->addJoin(AuthorPeer::ID, BookPeer::AUTHOR_ID, Criteria::INNER_JOIN);
$c->addJoin(BookPeer::PUBLISHER_ID, PublisherPeer::ID, Criteria::INNER_JOIN);
 
$c->add(PublisherPeer::NAME, 'Some Name');
 
$authors = AuthorPeer::doSelect($c);

If you are absolutely hell bent on returning your result set as objects, then I suppose the Propel approach is appealing, but it is more code in the end and there is an unavoidable learning curve (though admittedly not that daunting) to writing it.

If you're considering yourself a professional PHP application developer and not just a "coder" or "website designer", rather than avoiding SQL at all costs, you should be learning how to write good SQL.  I'm not sure where we got the idea that we needed a more succinct way to write queries without using SQL, since Structured Query Language is already succinct by design.

This is much the same argument as voiced against the myraid template engines out there...why build a template engine with its own simple syntax when PHP already is essentially a template engine?  Further, a similar argument has been made by Rasmus Lerdorf (also here), the father of PHP, with respect to the proliferation of frameworks.

Rather than use these drawbacks as an excuse to reject DALs (and template engines and frameworks for that matter), I am merely suggesting that the professional PHP developer recognize the limitations of these tools, and to know when it is more efficient to bang out an SQL statement than trying to contort your code and DAL class to deal with very complex queries.

One caveat I'd like to insert here at the end is ADOdb, perhaps the most popular DAL for PHP. I've used ADOdb in the past and like it. Rather than trying to abstract away all your SQL worries, ADOdb deals with the differences in connections and the PHP query functions across different database types, so that instead of obsessing about "mysql_query($sql)" versus "oci_execute($sql)", you focus only on your SQL. The advantage is that your apps become more portable/scalable across various relational db products.

Further reading:
Propel Object-Relational Mapping Framework
ADOdb Database Abstraction Layer
Wikipedia entry on Object-Relational Mapping

Firefox 3.5.3 Beta 1

{ No Comment }

imagesMozilla just released a new 3.5.3 Beta 1. It looks like just a bunch of bug fixes. (now this would have made a perfect tweet...)

Mac OS X 10.6 Snow Leopard: My upgrade experience

{ 2 Comments }

My Snow Leopard disk arrived Friday, and I promptly began upgrading my three Macs (A 2008 Mac Pro and early 2008 MacBook Pro at work, and a 2008 Mac Pro at home).

I've read very few horror stories so far about folks and their upgrades.  I had no issues whatsoever.  Install took about 1 hour for each of these three machines.

I likewise had virtually no issues with any of my apps.  Preference pane add-ons iStat Menus and Blueharvest didn't work.  Fortunately, Blueharvest's developer already had a new 10.6 compatible version available. Still waiting on something for iStat Menus however, but it is not a big operational loss for me to not know the exact load of my CPUs at any given moment.

hero_osx_2009082810.6 boots by default into 32-bit kernel mode. This is done to maximize compatibility with dozens of apps that haven't been updated to work in 64-bit mode.  10.6 is great in 32-bit mode, though if you're like me and cannot use the new Exchange features (We're in the midst of migrating from Exch 03 to 07 and my account hasn't been moved yet), you were left Friday a little bit disappointed by just how few visible perks Snow Leopard gives you.

So this morning I booted into 64-bit mode on my Mac Pro at the office (done by holding down "6" and "4" keys during boot, hold "3" and "2" during boot to go back to 32-bit).  All I have to say is "WOW."  This machines flies now...start up was multiple times faster (or at least seemed..I didn't time it) than before, and all my login items fired up at least twice as fast as before.

Mac Pro64-bit mode, as you might suspect, produced more software incompatibilities.  My Parallels 4.0 (mission critical for me to run a few Windows apps, as well as IE6 and IE7), would not load a VM.  The problem was a driver incompatible with 64-bit mode.  Big kudos to the folks at Parallels, however, because they released an update over the weekend that resolves the issues.

1Password 2 also encountered issues with 64-bit mode, but a few minutes spend cruizing the Agile Software website got me into the 1Password 3 BETA program and a 64-bit compatible version. Thanks to Brett Terpstra of TUAW for the tip.

Everything else seems to work, and work fantastically well.  I've read reports of Office for Mac 2008 not running well in 64-bit mode, but its been fine for me, if not much quicker to load than in 32-bit mode.

Other Apps I've tested in 64-bit mode so far:

Netbeans 6.7.1 - works just fine

The Gimp (in X11) - seems to work fine

LittleSnapper - hung on my first try

Panic Transmit - works fine

40% of Twitter is “pointless babble”

{ 2 Comments }

Ironically, this post would make a much more appropriate tweet, but nontheless I thought it worth posting here. Pear Analytics has audited Twitter content and found that only about 1 in 10 message has any real value, and as much as 40% of tweets are "pointless babble". For the curious, that category includes posts like "I"m having a sandwich."

Samuel Folkes: 17 PHP Practices That Should Be Banished Forever

{ No Comment }

stop-150x150Samuel Folkes has posted a great article about bad PHP programming habits.  In his article, titled 17 PHP Practices That Should Be Banned Forever, Folkes describes 17 specific behaviors which can lead to bad code, security holes, or both.

Not all of the 17 items are PHP-specific. Not properly commenting your code is of course a problem in any programming language.  This is also one I am ashamed to say is a problem for me.  Particularly when you are a one-man shop and you don't have anyone else working in or maintaining your code, commenting doesn't seem that necessary.  Having said that, I have always commented complex sections of code for my own benefit.  I've gotten better at more generalized commenting lately, particularly with writing Doc Block comments in my classes.  However, I would like to think that most of my code--at least the more recent stuff--is well written and logical enough that it is fairly self-explanatory to an experienced developer.

Other notable bad PHP habits include reliance on the ubiquitous Register Globals, failure to sanitize user input, not closing database connections, overuse of error supression, and using functions inside loop declarations.

One habit Folkes describes hit home with me in a very direct way.  He suggests reliance on short PHP tags (<?, <?=) is a no-no, principally because not all hosts have short tags enabled in php.ini, and also that potential conflicts can come up when working with XML, since XML documents begin with <?xml, the PHP parser may try to parse the XML open tag.

These are both valid concerns, particularly so if you are working extensively with XML, and/or if you are developing code to be distributed widely to server environments you have no control over.

I use the <?= tag extensively, since becoming a convert to Brian Lozier's PHP Templating Class.  Further, I develop in an enterprise environment, on a project which we do not intend to distribute, on a server where we (meaning the institution) do indeed control configuration.

I have developed a small number of XML documents generated from PHP scripts, but to this point my XML open tags have been encapsulated in strings ('<?xml') and would therefore never be parsed as PHP to begin with.  Perhaps due to my limited exposure to XML with PHP, I've not run into a scenario in which this compatibility problem would arise.

Finally, I've read recently on one site that short tags will be deprecated in PHP 6, then on another site I've read that <?= is about to make a comeback, since Zend Framework is pushing a Brian Lozier-esque PHP-as-template-engine approach.

We'll see.  Until I see more obvious handwriting on the wall regarding short tags, I'm sticking to my current approach.  As for the rest of Folkes' recommendations, they are well worth a read for any newbie or seasoned PHP developer.

BlueHarvest Fixes pesky ._DSstore and resource fork files

{ No Comment }

For those developing on a Mac in an otherwise non-Mac environment (Windows or Linux desktops and/or servers), you've undoubtedly run into the dreaded ._DSstore files.  These are resource files OS X creates for directories, and when connecting to a remote file system of another flavor, OS X will leave behind these files and cause you great torment from co-workers as you litter their machines and the servers with these files.  ._DSstore files are hidden by default in OS X, which is why you won't see them until and unless you access the given directory with another OS.

The simplest fix for this comes from Apple itself.  In this support document, Apple describes a Terminal command designed to turn off writing ._DSstore files to attached network drives.  The command looks like this:

defaults write com.apple.desktopservices DSDontWriteNetworkStores true

We use a virtual Windows Server as our dev environment, and I run Win XP under Parallels on my Mac in order to access some Windows-only software we still use.  I found even with the above terminal command, I was still leaving ._DSstore droppings everywhere I went.
Fortunately I found Blue Harvest, a system-preference pane add-on for OS X 10.4 and 10.5.  The software is $12.95 but it is free to try.  In the words of the developer:

BlueHarvest allows you to keep your disks and servers free of Mac "trails" by:

  • Automatically removing DS_Store files.
  • Automatically removing resource forks ("dot underscore" files).
  • Automatically removing hidden folders such as ".Trashes" from removable disks.
  • Providing simple Control-Click Finder based cleaning of disks, folders and Zip archives.

BlueHarvest is fully customizable (via a System Preferences Panel) and is a Universal binary, supporting Intel and PowerPC based Macs. BlueHarvest 2 requires 10.4.x or 10.5 and later.

Blue Harvest Preference Pane

Blue Harvest Preference Pane

So far I could not be happier with Blue Harvest.  Apple appears serious about making inroads into the enterprise office environment with Snow Leopard's upcoming native Exchange support.  Though I don't wish anything bad for the developer of Blue Harvest, one cannot escape the conclusion that such functionality should also be native if Apple really expects wide-spread adoption of Macs into Windows networks in workplaces around the world.

MySQL forks reveal uncertainty about Oracle’s plans

{ No Comment }

Ran across this article on Zend.com about Drizzle, a lightweight fork of MySQL intended for "cloud" applications.  As we see more fork projects and groups take MySQL in their own directions, I continue to wonder what Oracle's ultimate intentions are for the open source db now that it owns MySQL as part of its acquisision of Sun Microsystems.

Maybe tech and business industry types pointed out the painfully obvious fact that MySQL creates serious overlap with Oracle's existing relational db product lineup.  However, it has not been emphasised that the two products really cater to different markets.  Yes, there's some overlap, particularly in the low-cost rapid-application-development arena.  Are there low-cost small scale apps using Oracle? Yes, but I'm sure most are using the free "Express" version.  Are there huge enterprise scale apps using MySQL? Sure.  But, for the most part, I would wager that this overlap is negligible in comparison to the leverage that the gigantic MySQL installed base could give Oracle in terms of a gateway to new classes of potential customers for Oracle's other products and services.

IE7.js a universal solution to IE6 craptastic-ness?

{ No Comment }

More thoughts on this later, but for now, just check out Dean Edwards' IE7.js javascript library, which causes IE to behave like a standards-compliant browser. Eric Meyer has some great thoughts about IE7.js as well.  Note that both IE7.js and Eric's blog post have been around a while, but this is still good stuff for anyone having to suffer with a large IE6 installed base (myself included).