Tag: php

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...

Extending Singletons

This morning, I was wondering about how to extend a singleton class such that you could retrieve the new class when retrieving the singleton later. In particular, Zend_Controller_Front is a singleton, but what if I want to extend it later? A number of plugins in the Zend Framework, particularly view helpers and routing functionality, make use of the singleton; would I need to alter all of these later so I could make use of the new subclass?

For instance, try the following code:

class My_Controller_Front extends Zend_Controller_Front
{}

$front = My_Controller_Front::getInstance();

You'll get an instance of Zend_Controller_Front. But if you do the following:

class My_Controller_Front extends Zend_Controller_Front
{
    protected static $_instance;

    public static function getInstance()
    {
        if (null === self::$_instance) {
            self::$_instance = new self();
        }

        return self::$_instance;
    }
}

$front = My_Controller_Front::getInstance();

You'll now get an instance of My_Controller_Front. However, since $_instance is private in Zend_Controller_Front, calling Zend_Controller_Front::getInstance() will still return a Zend_Controller_Front instance — not good.

However, if I redefine Zend_Controller_Front::$_instance as protected, and have the following:

class My_Controller_Front extends Zend_Controller_Front
{
    public static function getInstance()
    {
        if (null === self::$_instance) {

            self::$_instance = new self();
        }

        return self::$_instance;
    }
}

$front = My_Controller_Front::getInstance();

Then the any time I call getInstance() on either My_Controller_Front or Zend_Controller_Front, I get a My_Controller_Front instance!

So, the takeaway is: if you think a singleton object could ever benefit from extension, define the static property holding the instance as protected, and then, in any extending class, override the method retrieving the instance.

Continue reading...

exuberant ctags with PHP in Vim

One reason I've heard PHP developers use for adopting an IDE when developing is the ability to click on a class or function name and jump to the declaration. Sounds like magic, and it's definitely something I've desired.

One way I get around it is by adopting PEAR coding standards for naming my classes. Since they define a one-to-one mapping of class name to the file system (substitute the underscore character (_) with the directory separator), I can usually very quickly and easily open a class file, particularly if I start in the base directory of the project install.

Today, however, I found exuberant ctags, a library which can be used to generate an index file mapping language objects to source files and the line in the source file where they are declared. Contrary to its name, it's not just for the C language; it currently supports 33 different programming languages, including PHP.

I decided to try it out on the Zend Framework core library today. At first run, it was pretty useful. However, it was only mapping classes, and, in addition, only those defined with the single word 'class' — abstract classes and interfaces were entirely left out. So, I looked into the documentation to see if I could change the behaviour.

And, being a Unix program, of course I could. First off, you can add functions to the items it indexes with a simple flag. Additionally, you can use POSIX regular expressions to refine what it searches.

I whipped up the following script to create my tags index:

###!/bin/bash
cd /path/to/framework/library
exec ctags-exuberant -f ~/.vim/mytags/framework \
-h \".php\" -R \
--exclude=\"\.svn\" \
--totals=yes \
--tag-relative=yes \
--PHP-kinds=+cf \
--regex-PHP='/abstract class ([^ ]*)//c/' \
--regex-PHP='/interface ([^ ]*)//c/' \
--regex-PHP='/(public |static |abstract |protected |private )+function ([^ (]*)//f/'

This script creates the tag index in the file $HOME/.vim/mytags/framework. It scans for PHP files recursively through the tree, excluding any files found in a .svn directory (I'm using a checkout from the subversion repository). The file paths in the index are created relative to the tags file; this was important, because if this wasn't provided, vim was unable to jump to the file, as it couldn't find it. --PHP-kinds=+cf tells it to index classes and functions. Next, I've got three regular expressions. The first tells it to match classes beginning with 'abstract class' as classes. The second tells it to match interfaces as classes. The last is so that PHP 5 methods, which begin with a visibility operator, to be matched as functions.

Once the index file is generated (it takes less than a second), all you need to do in vim is tell it to load it: :set tags=~/.vim/mytags/framework. At this point, you can do all sorts of fun stuff. Place the cursor on a class name or method name, anywhere in it, and hit Ctrl-], and you'll jump to the file and line of its declaration; Ctrl-T then takes you back. If you change the invocation to Ctrl-W ], it will split the current window and open the declaration in the new pane. (If you're familiar with how help works with Vim, this should seem pretty familiar.)

One more reason to stick with Vim for your PHP editing needs. :-)

Continue reading...

PHP decoding of Javascript encodeURIComponent values

Recently, I was having some issues with a site that was attempting to use UTF-8 in order to support multiple languages. Basically, you could enter UTF-8 characters — for instance, characters with umlauts — but they weren't going through to the web services or database correctly. After more debugging, I discovered that when I turned off javascript on the site, and used the degradable interface to submit the form via plain old HTTP, everything worked fine — which meant the issue was with how we were sending the data via XHR.

We were using Prototype, and in particular, POSTing data back to our site — which meant that the UI designer was using Form.serialize() to encode the data for transmission. This in turn uses the javascript function encodeURIComponent() to do its dirty work.

I tried a ton of things in PHP to decode this to UTF-8, before stumbling on a solution written in Perl. Basically, the solution uses a regular expression to grab urlencoded hex values out of a string, and then does a double conversion on the value, first to decimal and then to a character. The PHP version looks like this:

$value = preg_replace('/%([0-9a-f]{2})/ie', \"chr(hexdec('\1'))\", $value);

We have a method in our code to detect if the incoming request is via XHR. In that logic, once XHR is detected, I then pass $_POST through the following function:

function utf8Urldecode($value)
{
    if (is_array($value)) {
        foreach ($key => $val) {
            $value[$key] = utf8Urldecode($val);
        }
    } else {
        $value = preg_replace('/%([0-9a-f]{2})/ie', 'chr(hexdec($1))', (string) $value);
    }

    return $value;
}

This casts all UTF-8 urlencoded values in the $_POST array back to UTF-8, and from there we can continue processing as normal.

Man, but I can't wait until PHP 6 comes out and fixes these unicode issues…

Continue reading...

Overloading arrays in PHP 5.2.0

Update: I ran into issues with the ArrayObject solution, as there was a bug in PHP 5.2.0 (now fixed) with its interaction with empty() and isset() when used with the ARRAY_AS_PROPS flag. I tried a number of fixes, but eventually my friend Mike pointed out something I'd missed: as of PHP 5.1, setting undefined public properties no longer raises an E_STRICT notice. Knowing this, you can now do the following without raising any errors:

class Foo
{
    public function __set($key, $value)
    {
        $this->$key = $value;
    }
}

$foo        = new Foo();
$foo->bar   = array();
$foo->bar[] = 42;

This is a much simpler solution, performs better, and solves all the issues I was presented. Thanks, Mike!


Continue reading...

svn:externals

I was recently working with someone who was using Zend Framework in their project. To keep things stable and releasable, he was doing an export of framework into his repository and checking it in. Since files change so much in the ZF project currently, instead of doing an rsync from a checkout into his own repository, he decided instead to delete the directory from the repository and re-add it everytime he was updating framework.

This seemed really inefficient to me, especially considering that it made it incredibly difficult to merge changes from his development branch into his production branch (deleting and re-adding directories breaks the merge process considerably). I knew there had to be a better way.

I'd heard of the svn:externals property before, but never really played with it. As it turns out, it exists for just this very type of situation. The problem is that the documentation of svn:externals in the SVN book doesn't indicate at all how the property should be set, and most howto's I've read omit one or more very important details. I finally figured things out through some trial and error of my own, so I'm going to share the process so others hopefully can learn from the experience as well.

It's actually pretty easy. This assumes that your project layout looks something like this:

project/
    branch/
        production/
    tag/
    trunk/
  • In the top of your project trunk, execute the following:

    $ svn propedit svn:externals .
    
  • This will open an editor session. In the file opened by your editor, each line indicates a different external svn repo to pull. The first segment of the line is the directory where you want the pull to exist. The last segment is the svn repo URL to pull. You can have an optional middle argument indicating the revision to use. Some examples:

    • Pull framework repo from head:

      framework http://framework.zend.com/svn/framework/trunk
      
      • Pull framework repo from revision 2616:
      framework -r2616 http://framework.zend.com/svn/framework/trunk
      
  • After saving and exiting, update the repo:

    $ svn up
    
  • Commit changes:

    $ svn commit
    

One thing to note: any directory you specify for an svn:externals checkout should not already exist in your repository. If it does, you will get an error like the following:

svn: Working copy 'sharedproject' locked
svn: run 'svn cleanup' to remove locks

I show using revisions above; you could also pin to tags by simply checkout the external repository from a given tag. Either way works well.

Then, when moving from one branch to another, or from the trunk to a branch, you simply set a different svn:externals for each branch. For instance, your current production might check from one particular revision, but your trunk might simply track head; you then simply determine what the current revision being used is on your trunk, and update svn:externals in your production branch when you're ready to push changes in.

Hope this helps some of you out there!

Continue reading...

Getting XDebug working with PHPUnit for code coverage reports

I've been playing with PHPUnit a lot of late, particularly with framework development. One thing that's always hard to determine is how well your code is exercised — basically, how much of the code is tested in the unit tests?

In PHPUnit 3, you can now generate code coverage reports using XDebug, and the usage is very simple:

matthew@localhost:~/dev/zend/framework-svn/tests$ phpunit --report ~/tmp/report AllTests

The above command creates a coverage report directory report under my tmp directory. You can then browse through the reports in a web browser and visually see which lines of code were executed during tests, and which were not, as well as a synopsis showing the percentage of coverage for any given file or directory — useful stuff indeed!

So, what's the problem? Getting XDebug running.

The executive summary:

  • Enable the extension using zend_extension = /full/path/to/xdebug.so, not as extension = xdebug.so, in your php.ini

  • Use the setting xdebug.default_enable = Off in your php.ini.

  • If compiling using pecl or pear, make sure it compiles against the correct PHP; if not, hand compile it using:

    $ /path/to/phpize
    $ ./configure --with-php-config=/path/to/php-config
    $ make
    $ make install
    

For the detailed narrative, read on.

Continue reading...

MVC changes in Zend Framework

Several months ago, Andi asked me to take the role of lead developer on a refactoring of the Zend Framework MVC components. I agreed, though somewhat reluctantly; I already maintain another MVC library, and wasn't sure how well I could fill the shoes of people like my friends Mike, who had done the initial development on the controller classes, and Paul, who provided Zend_View.

The experience has been incredibly rewarding, however, and I've had the chance to pick the brains of and work with some top-notch developers in the process. In the next week or so, we'll be releasing version 0.6.0 of the framework, and it will include much of my work in the MVC components as part of the core distribution. A big thanks to all those who have contributed opinions, design help, code, tests, and documentation; another thank you goes to Andi for trusting and supporting me in this endeavor.

So, what are the changes? Read on to find out…

Continue reading...

PHP Best Practices

Yesterday, Mike and I presented our session "Best Practices of PHP Development" at this year's Zend Conference. It was a marathon three hour tutorial first thing in the morning, and we had an incredible turnout, with some fairly enthusiastic people in the audience.

Download the slides slides for PHP Best Practices.

Continue reading...

ZendCon: Best Practices Session

As Mike already noted, he and I are presenting a session on "Best Practices of PHP Development" at this year's Zend Conference and Expo. It has been my fortunate experience to work with Mike in the past, and, as he noted, we had so much fun presenting during last year's conference, we thought we'd do it again.

The session is a pre-conference tutorial session, running for 3 hours on Monday morning, 30 October 2006. Currently, we're shaping up the session into the following subject areas:

  • Programming Practices

    • Coding Standards
    • Test Driven Development and Unit Testing
    • Project Documentation
  • Tools and Processes

    • Software Configuration Management (SCM)
    • Collaboration tips and tools
    • Deployment

Emphasis is going to be on working in teams, particularly those operating in geographically diverse areas. With roughly 30 minute blocks per topic, we've certainly got plenty to cover!

If you're coming to the conference, we look forward to seeing you in our session!

Continue reading...