Blog Posts

ZendCon is over at last

ZendCon '07 is finally over, the dust has settled, and I finally find myself with some time alone… practically the first I've had since Sunday. The week was fantastic, and I had many good conversations and brainstorming sessions. Oh, and I ended up giving three different sessions, so it's time for links to slides and materials:

  • Best Practices of PHP Development. Sebastian, Mike, and I presented a full-day tutorial on PHP development best practices, focussing primarily on testing and testing strategies, but also covering coding standards, usage of SCM tools, and deployment. There were a ton of questions from the attendees, and Sebastian even whipped out some extra slides at the end showing new and little-known features of PHPUnit. Basically, reading the slides won't really indicate what we covered, but is more of a general outline. It was an honor and pleasure to work with Sebastian and Mike on this, and I hope we can do it again in the future some time.
  • Zend Framework MVC Quick Start. This was basically the same session I did in my webinar a couple weeks ago, with a few corrections and a small demonstration. Cal put me on directly following Terry Chay, in the largest of the four session rooms — the one where all the keynotes occurred — talk about intimidating! Amazingly, the session was really well attended — others I talked to estimate between 100 and 150 people showed up. The most amazing part, though, was that when I asked how many people knew what 'MVC' was, I don't think there was a single person who didn't raise their hand — definitely a sign of how well accepted the pattern now is in PHP.
  • AJAX-Enabling Your Zend Framework Controllers. I did this talk for the Unconference, mainly because its a topic I've been interested in and wanted to present. In it, I detailed how to ajax-enable an application through some easy tricks with Action and View Helpers and using JS to decorate your existing application. The reference app I used was a pastebin, and I've got code for both Dojo and Prototype flavors available:

The two highlight keynote speakers, for me, were definitely Joel Spolsky and Cory Doctorow. Neither spoke about PHP, but both spoke about topics that PHP developers should take to heart. Perhaps I'll elaborate on those in another post.

Another bonus for me was the number of old and new friends alike I got to see — I had many good conversations with Paul M. Jones, Nate Abele, Ivo Jansch, and Ralph Schindler, and opportunities to finally meet fellow co-author Lig Turmelle, Ben Ramsey, Chris Shifflet (dude, we've been to four conferences together, and never yet met!), and many, many others. I was also overwhelmed by the number of Zend Framework users who sought me out either to ask me questions or simply thank me and the others on the team for the project; I'm deeply honored that I can work on a project that affects so many developers.

And now for some down time to recuperate…

Continue reading...

oh, yeah, zendcon...

I don't know why I haven't blogged this sooner, but, yes, I'll be speaking once again at ZendCon:

I'll be presenting a number of times:

  • On Monday, I join Sebastian Bergmann and Mike Naberezny in a full-day tutorial session on PHP Development Best Practices and Unit Testing. This expands on what Mike and I did last year, and will more heavily emphasize the role of testing in the development process — arguably the most important best practice you can adopt.
  • On Tuesday monrning, I'll present a Zend Framework MVC Quick Start. This talk is based on a webinar I recently gave for Zend, and covers the various pieces of the MVC layer in Zend Framework.
  • Tuesday evening, I'll present an Unconference session on Ajax-enabling your Zend Framework controllers. I don't know yet if I'll need the whole hour, but I can probably fill it up with some examples of decorating your apps with AJAX.

Looking forward to seeing you all there!

Continue reading...

Zend Framework MVC Webinar posted

Last Wednesday, I presented a webinar for Zend entitled "MVC applications with Zend Framework". We had more than 50 attendees, most of whom stayed on the whole time. For those of you who attended, thanks for the great questions and comments.

If you would like to view the webinar, download the slides, or download the example code (a hello world app), visit the Webinar page and look for the presentation; as of today, it's the first one on the list, but that will change as more webinars are presented.

Continue reading...

NYPHP Zend Framework Presentation

This past Wednesday, Zend's Chief Marketing Officer, Mark de Visser, and myself joined the NYPHP group for a special event meeting. Mark presented information on Zend's development stack and toolset (which I entirely missed, as I was still in transit), and I came in to give an overview of Zend Framework.

There were some great questions, and nice discussions following the event. If you live in New York and do PHP for a living, and haven't attended, you should; if you're ever visiting the area, see if you can attend a meeting!

Here are the slides. They're done using S5, a browser-based slideshow system. Simply unzip and double-click on index.html to start viewing.

Continue reading...

File_Fortune refactored

Over the past few evenings, I've refactored File_Fortune to have it implement Iterator, Countable, and ArrayAccess — basically allowing it to act like an array for most intents and purposes. As a result, I've eliminated the need for the File_Fortune_Writer package, and greatly simplified the usage.

(Note: sure, File_Fortune may not be that big of a deal, but over 1000 downloads in the past two years indicates somebody is using it. Plus, it powers the random quotes on the family website. :-) )

As some examples:

require_once 'File/Fortune.php';

// Initialize and point it to a directory of fortunes
$fortunes = new File_Fortune('/path/to/fortunedir');

// Retrieve a random fortune 
// (works with either a directory or a single fortune file)
echo $fortunes->getRandom();

// Set to a specific fortune file:

// Loop through and print all fortunes
foreach ($fortunes as $fortune) {
    echo str_repeat('-', 72), "\n", $fortune, "\n\n";

// Hmmm.. let's change one:
$fortunes[7] = "I never really liked that fortune anyways.";

// No need to explicitly save, as it's done during __destruct(), 
// but if you really want to:

// Let's add a new fortune:
$fortunes->add('This is a shiny new fortune!');

// and now we'll verify it exists:
$index = count($fortunes) - 1;
echo $fortunes[$index];

All-in-all, it's a much better interface. Lesson learned: when porting code from other languages, it pays to take some time and determine if there might be a better API in your own.

In upcoming releases, I hope to modify the backend to use PHP's Streams API instead of direct file access, and also to allow providing a list of fortune files explicitly. After that, I should be ready for the initial stable release.

Update (2007-07-10): fixed parse error in examples

Continue reading...

Globals, continued

Update: Sara has pointed out a flaw in my last case. The file loadFileWithGlobals.php was incorrectly loading the wrong file — it should be loading withGlobals2.php (updated now). When it does, access to baz2 works as it should.

As I note to in my comment, however, I stand by my original rant: relying on globals for your applications is a bad practice, as it makes them difficult to integrate with other applications later. Developers using your application should not need to hunt down exactly when a global is first declared and explicitly push it into the global scope in order to get that application to integrate with others. Use other means, such as singletons or registries, to persist configuration within your applications.

In my last entry, I evidently greatly simplified the issue to the point that my example actually didn't display the behaviour I had observed. I'm going to show a more detailed example that shows exactly the behaviour that was causing issues for me.

First off, this has specifically to do with including files from within functions or class methods that then call on other files that define values in the global scope. In the original example, I show an action controller method that includes the serendipity bootstrap file, which in turn loads a configuration file that sets a multi-dimensional array variable in the global scope. Without first defining the variable in the global scope, this method of running serendipity fails.

Now, for the examples.

Continue reading...

PHP globals for the OOP developer

Update: I evidently simplified the issue too much, and have had several people rightly comment on the bogosity of the issue. However, there are still situations where $GLOBALS does not act as expected, and I outline these in my next entry.

In my previous entry, I ranted about the use of globals in popular PHP applications, and how they make embedding said applications difficult. I develop using object-oriented practices, and can honestly say I can't recall ever having slung a global variable around in my own code. Globals seem hackish to me, and as a result, trying to get applications that use them to behave correctly has been a challenge.

One of the applications I had in mind was Serendipity, the software that powers this blog. I was attempting to create a Zend Framework action controller that wraps my s9y instance so that I can do things such as apply ACLs from my website to selected entries, as well as pull the sitewide skeleton out from s9y so that I only have to maintain one version of it (I had one version for s9y, and another for my own content featured on the site (resume, contact form, etc.).

I tried importing the various config files into my action method prior to invoking the actual s9y bootstrap, but no dice. I also tried modifying the s9y config files to use the notation $GLOBALS['serendipity'] around the serendipity configuration variables (s9y uses a single multi-dimensional array for all configuration options). This didn't work, either; s9y functions that called global $serendipity were still getting a null value.

So, I did a little closer reading in the manual section on predefined variables, I discovered something interesting in the description of $GLOBALS (emphasis mine):

Contains a reference to every variable which is currently available within the global scope of the script.

Interestingly, the section on variable scope didn't make this distinction at all. Basically, if the variable you reference via $GLOBALS does not already exist, assigning it does nothing. It doesn't even raise a notice. It just silently goes ahead, leaving you thinking you set a new global variable, but in fact, you cannot assign new globals via $GLOBALS; you can only modify existing variables in the global scope.

So, I got around the issue by putting this in my front controller bootstrap:

$serendipity = null;

After that, I was able to create a wrapper action controller for s9y very easily:

/** Zend_Controller_Action */
require_once 'Zend/Controller/Action.php';

 * Serendipity integration
 * @uses       Zend_Controller_Action
class S9y_IndexController extends Zend_Controller_Action
    public function init()
        // New ViewRenderer helper in ZF incubator; telling it not
        // to autorender a view script when done
        $this->_helper->viewRenderer->initView(null, null, array('noRender' => true));

    public function indexAction()
        global $serendipity;
        chdir($_SERVER['DOCUMENT_ROOT'] . '/path/to/s9y');
        include './index.php';

Note that I don't do any output buffering; this is because the ZF dispatcher takes care of that for me. All I need to do is execute the s9y bootstrap.

So, the lesson to learn from all this: if you need to wrap an application that uses globals, find out what all of them are, and declare them in the global namespace — just setting them to null is enough — in your application bootstrap.

Continue reading...

Start Writing Embeddable Applications

Clay Loveless wrote last year an article entitled Stop Writing Loner Applications in which he ranted about all the monolithic applications that act like they're the only kid on the block when it comes to user authentication. Basically, if you want to create a site that utilizes several third-party, off-the-shelf PHP apps (say, a forum, a blog, and a wiki), getting a shared authentication to work between them can be more than a little painful.

I've hit a similar problem repeatedly the past couple months: most of these apps simply are not embeddable, at least not without modifying the source.

"Why embed?" you ask. Simple: if I'm creating a site that has one or two of these applications, but also my (or my company's) own custom functionality, I may want to ensure that certain elements are present on all pages, or that I can control some of the content in all pages: a unified header and footer, ability to inject statistic tracking javascript, etc.

The predominant attitudes are either, "Don't embed our app, embed your app in ours," or "Just modify the templates." Neither of these solutions is acceptable.

Continue reading...

BostonPHP Framework Presentations

Last Wednesday evening, I had the honor of presenting Zend Framework to BostonPHP, as part of an ongoing series they're holding on PHP frameworks; Horde was also represented as part of the evening's fare. It was the first time I've attended a UG, so I got the double whammy of that and being a presenter. Oh, make it a triple whammy — Boston is a 3+ hour drive from the Burlington, VT area I now call home.

All in all, the presentations went quite well. It was particularly fun to see what my friend Chuck Hagenbuch has been up to with Horde; his description and demonstration of RDO, or "Rampage Data Objects" was very cool (I really like the idea of "Horde on the Rampage" -- it's a very funny image for me), as was his working demonstration of using WebDAV to pull results via PHP in the Mac Finder.

A lot of people are interested in and working regularly with Zend Framework, at least based on the questions I was receiving. Attendees ranged from the "what does Zend do" category to the "We're standardizing on Zend Framework and use Zend products throughout our stack" category. The bulk of the comments I received were either of the flavor "I really like what I'm seeing" or wondering how mature/stable Zend_Db is. Unfortunately, at the time I was preparing the slides, there were many features in Zend_Db that can cause headaches, and I took some time to point these out; however most of these are soon to be history, due to the work of Bill Karwin and Simon Mundy, who are pushing to get a stable, usable DB abstraction layer out the door for ZF 1.0.

During the joint question and answer session, I started getting some particularly tough, pointed questions from one member of the group. I wasn't getting particularly rattled, but the moderator, Seth, decided to intervene and introduce me to my interlocutor — none other than Nate Abele of the CakePHP project. In the end, he joined Chuck and myself at the front of the room, and we had a nice panel discussing how the various frameworks handle different issues.

If you're ever in the Boston area, check to see if BostonPHP is having a meeting; it's a fun group.

My slides are now available; I've revised them slightly to fix some syntactical errors I noticed during the presentation, but otherwise they're what I presented. You may also want to check out the podcast.

Continue reading...

Back on Linux Again

A little over a year ago, I stopped using Linux as my primary desktop due to the fact that a number of programs we were using were Windows dependent. Despite getting coLinux running, I've never been completely satisfied with the setup. I missed being able to paste with my middle-mouse button, and I was constantly having character encoding issues pasting back and forth between PuTTY and windows apps, couldn't access mail easily between my coLinux and Windows partitions, and overall felt that I was losing out on some productivity by not having a native linux environment as my primary OS.

Last week, we had an infrastructure change at work, and I basically realized that my Windows + coLinux setup was going to get in the way of productivity -- and that, at this point, there were now Windows applications tying me to that OS. So, I decided it was time to go back to Linux.

Continue reading...