I'm getting ready to move in another week, and thought it was time to push a new release out the door… before life descends into utter chaos.
Cgiapp 1.7.0 adds a plugin architecture (which has been present in the perl version since last autumn). Plugins register with the class, and, once registered, their methods may be called from your Cgiapp-based class as if they were part of it through the magic of overloading. This allows for a standard library of utilities to be written — such as form validation (a sample class for this has been provided utilizing HTML_QuickForm), authentication, error logging, etc.
Additionally, I created a
Cgiapp5 class that inherits from and extends Cgiapp.
Along with it is a
CgiappErrorException class that can handle PHP errors and
rethrow them as exceptions. Combined, the two create some very elegant run mode
error handling that simply isn't possible in PHP4.
php|Tropics last week was excellent, and I'm not even sure where to begin for a recap. I started journaling while there, but found I simply did not have enough time (or bandwidth — my one complaint about the conference) to keep up.
The trip down was hellish. I'd lost my birth certificate, and was turned away at the ticket counter due to improper documentation. I was able to reschedule for several hours later, and had just enough time to go home, look futilely for my birth certificate, and then run down to the town clerk office in Bolton to get a certified and notarized letter proving my voter registration. Which got me on the plane, but I still ended up having to sign a notarized affidavit of citizenship before my final flight from Houston could take off.
The resort where the conference was held is called Moon Palace Resort, and is one of a string of five or more 'Palace' resorts on the Mexican Riviera below Cancun. The place is huge — there are two lobby areas, and each serves what looks like a couple thousand rooms. You can't help but get exercise while there, because there's simply so much ground to cover.
Marco Tabini gave the keynote, and kept it short and sweet. To my mind, he covered one primary point: the PHP job market sucks for pay. As he put it, why does an assembly line worker at Ford get paid $35/hour, while the average PHP developer is paid $15/hour? This is not to belittle the assembly line worker, but more to ask the question of whether or not a PHP developer is inherently less skilled. Marco feels that the way to boost PHP wages is to produce a standard educational corpus and licensing program — and educate employers as to why someone who has taken them deserves to be paid more. (I'm still not sure how I feel about his conclusions, but they're certainly food for thought — as I'm not being paid much more than the PHP average.)
Rob and I skipped out on the first two sessions. To our mind, we weren't as interested in them as other sessions, and we weren't going to have much free time while there. We put on the swim trunks and took a stroll through the pool. Yes, a stroll. I wish I could find a map that shows just how long and serpentine the pool there is; you can easily get a good workout just going for a stroll in the pool.
And strolling is thirsty business, so we strolled over to a swim-up bar. Now, one excellent thing about the location is that the resort is an "all-inclusive" resort — meaning that all food and drink is included in the price. So, we ordered margaritas, since it was noon where we live. They were okay, a little weak… and Rob noted that the bartender wasn't using anything off the top shelf. "What do you think we need to do to get him to use the Sauza?" asked Rob, to which I replied, "I think you just ask for it." So, next round, "Margaritas con Sauza, por favor."
And so it goes.
Strolling also included the beach, a wonderful expanse of white sand overlooking the azure water of the Caribbean. I spent a lot of time just sitting under coconut trees staring out over the sea; I can see how tempting it would be to retire on the Caribbean.
We started attending sessions that afternoon, and only missed one more over the course of the conference. I did get some excellent information from a number of sessions — but one thing in particular I got out of the conference as a whole is how far advanced is the setup Rob and I have put together at NGA. Our web cluster is almost as good as it gets without pouring money into commercial databases and support (though Ilia Alshanetsky's web acceleration session gave me a ton of information on tuning the relations between php, apache, and the OS); we've standardized on PEAR and are using it well; we're filtering data reasonably well (though we can always do better); etc. I often feel like I'm behind the curve when it comes to our technology, so the conference was a welcome boost to the ego.
On day 2, I ran into Paul Jones, with whom I've emailed once or twice, and on whose blog I've commented several times. We immediately started hanging out, and talking shop. Which began the other important aspect of the conference: the social networking.
In day-to-day practice, I really only get to talk code and program with one other person, Rob. This is fine, but it leads to a narrow exposure. Going to the conference gave me a chance to go over code and coding philosophy with a larger variety of people — my peer group, if you will. I got to see that, if you're not working for a large corporation, you do the same shit I do every day — programming, installing and tuning servers, help desk issues, everything; coding in PHP is only one aspect of your busy life. It was actually refreshing to see that I'm not alone.
A group of six of us got together that second evening, and ate out at one of the 'restaurants' (there are several eateries at the resort; not really restaurants, 'cause you don't have to pay, and they're all buffets) overlooking the Caribbean. As we were talking, we commented on how the networking amongst each other was probably the best part of the conference — and how it would be nice if the speakers would deign to join us.
Ask and ye shall receive. Later that evening, as we stood around the 'swing bar' (a little tiki bar with swings instead of bar stools, out on an island of the large, serpentine pool), we were gradually joined by speakers, including Marcus Boerger, Wez Furlong, Derick Rethans, and Lukas Smith. We had some great discussions that started devolving in indirect proportion to the amount we drank (well, not really devolving, but certainly migrating to other non-coding topics…)
Unfortunately, Rob and I had to cut out around 11:30, as we were taking the Zend Certification Exam at 8 the following morning. I quit drinking between 9:30 and 10… Rob had not, so he got to do the exam with a hangover. All in all, I found the exam less difficult than the study guide, but certainly full of tricks meant to foil you.
The final evening had a similar conclusion to the night before, only with even more participants, including Jason Sweat and Ilia. This time there were no exams to follow, and we stayed up until 1:30 (and later for some people).
Looking back, I see I wrote very little about the actual conference — which seems odd, as it was the central event. There were certainly some excellent presentations, and a lot of great material — much of it I have not been able to find elsewhere. Hopefully I'll find some time to blog about it in the coming weeks.
I didn't take many pictures, and I need to get a gallery going anyways. Rob, however, took a ton of pictures and put them up on his site each day. You can view them at his gallery; I'll put direct links to the individual galleries later.
So, if you get a chance, attend the next PHP conference you can possibly afford, and spend as much time as possible getting to know your fellow PHP code monkeys; the benefits are, to use an oft-used marketing phrase, priceless.
I've been wanting to play with
HTML_QuickForm for quite some
time, but the documentation has looked rather sparse and scary regarding the use
HTML_QuickForm with Smarty. Since I've been busy
at work, and I haven't wanted to take the time to learn a new library, I've
simply been putting it off.
Last night, I browsed through the package documentation, and noticed a link to an HTML_QuickForm Getting Started Guide by Keith Edmunds. I was pleased to discover that he also has a guide to using Smarty with HTML_QuickForm. I got started with these tutorials, and found them excellent. I found myself wanting a little more meat afterwards, and found that I could now turn to the PEAR docs and actually make sense of it all.
While I think Mr. Edmunds tutorials are great for starters, I found that there were a few pointers I could have used right off the bat. I present them here for you.
I've made two releases of Cgiapp this week, 1.6.2 and 1.6.3.
1.6.2 was tested in a PHP 4.3.4 environment, and features several bugfixes that
give PHP4 compatibility. 1.6.3 fixes a change in
load_tmpl() that broke
As usual, Cgiapp is available on the SourceForge website, as is a complete Changelog and documentation.
I've been working on the Cgiapp roadmap, and particularly on the plugin architecture. I'd been operating under the assumption that I'd have to make a PHP5-specific release (Cgiapp2) to allow this feature. However, it turns out I'm wrong.
A user noted in a comment to my blog on the 1.6.0 release that I'd included a
public keyword in the
s_param() method declaration… which caused
compilation to fail in PHP4. So, quick on the heels of that release, I've
released 1.6.1 to correct this issue. Downloads are available at the
Cgiapp 1.6.0, "Wart Removal", has been released!
This release does not add any new methods, but adds quite a lot in terms of functionality:
s_delete()now works properly.
s_param()now behave gracefully when given bad data (as do a number of other methods)
header_*()suite now function as documented.
croak()no longer echo directly to the output stream (and, in the case of
croak(), die); they use
trigger_error(). This will allow developers to use
croak()as part of their regular arsenal of PHP errors — including allowing PHP error handling. Additionally, most
croak()calls in the class were changed to
carp()as they were not truly fatal errors.
pear install Cgiapp-1.6.0.tgzto get Cgiapp installed sitewide on your system!
As usual, Cgiapp is available at the Cgiapp website.
As promised in my earlier entry from today, here's my quick-and-dirty tutorial on unit testing in PHP using phpt.
First off, phpt test files, from what I can see, were created as part of the PHP-QA effort. While I cannot find a link within the PHP-QA site, they have a page detailing phpt test files, and this page shows all the sections of a phpt test file, though they do not necessarily show examples of each.
Finally, before I jump in, I want to note: I am not an expert on unit testing. However, the idea behind unit tests is straightforward: keep your code simple and modular, and test each little bit (or module) for all types of input and output. If the code you're testing is a function or class method, test all permutations of arguments that could be passed to it, and all possible return values.
Okay, let's jump in!
I've been tinkering with Unit Testing for around a year now, and have tried using PHP Unit as well as Simple Test. It was while following the Simple Test tutorial that I finally grokked the idea of unit testing, and so that has been my favored class for testing.
However, I find writing the tests tedious. In Simple Test, as in PHP Unit, you need to create a class that sets up the testing harness, and then you create a method for each test you wish to run, and so on… I found it incredibly time consuming. Additionally, I found the test harness often felt like a foreign way of testing my code; I was setting up a structure I would never use my code in, typically. All in all, I only test when I have extra time (which is rare) or when I'm really having trouble nailing down bugs (and the unit tests often don't help me find them).
Recently, I've been hearing some buzz over on the PEAR lists and the blogs of some of its developers about 'phpt' tests. From what I hear, phpt tests sound very similar to how one tests in perl (though I've never written perl tests, I've at least glanced through them). However, until recently, I haven't seen any documentation on them, and installing PEAR packages via pear doesn't install tests.
We got a copy of PHP5 Power Programming a few weeks ago, and in the section on preparing a PEAR package was a brief section on phpt tests. The section was small, and when I looked at it, my immediate thought was, "it can't be that simple, can it?"
So, I decided to try it out with Cgiapp. A few minutes later, I had some working tests for my static methods. "Hmmm," I thought, "That was easy. Let's try some more."
Turns out they're kind of addictive to geeks like me. In a matter of a few hours, I'd knocked out tests for over half the functionality, and disccovered, to my chagrine and joy, a number of bugs and bad coding practices… which I promptly corrected so I could get that magical 'PASS' from the test harness.
In the process of writing the tests, my understanding of the tool evolved quite a bit, and by the end, I had the knack for it down. I'll blog later about some of the ways I made them easier to use for myself — and how I made them more useful for debugging purposes.
I just had to add a note over on PHP.net regarding abstract classes and methods: Object Abstraction.
I'm working on Cgiapp2, which is a PHP5-only implementation of Cgiapp that is built to utilize PHP5's new object model as well as exceptions. One thing I decided to do, initially, was to make it an abstract class, and to mark the overridable methods as abstract as well.
In testing, I started getting some strange errors. Basically, it was saying in my class extension that an abstract method existed, and thus the class should be marked as abstract, and, finally, that this means it wouldn't run.
What was so odd is that the method didn't exist in the extension at all.
So, I overrode the method in the extension… and voila! Everything worked fine.
The lesson to take away from this is quite simple: if the method does not need to be present in the overriding class, don't mark it as abstract. Only mark a method as abstract if:
Now I need to update my source tree…. :-(