Paul M. Jones

Don't listen to the crowd, they say "jump."

Savant: Revoking the 2.3.0 release

I am revoking the Savant 2.3.0 release from yesterday. The file will still be available, but I can no longer vouch that it will work everywhere for everyone, and I cannot promise that the new function provided therein ("calling of plugins as native methods") will be in a future Savant 2.x release. I recommend reverting to 2.2.0, particularly for PHP5 users.

For 2.3.0, the only major change was that you could call plugins as native Savant functions through the magic of overload() and __call(). The use of __call() turned out to be unwise, as it exposed a serious compatibility issue between PHP4 and PHP5.

I'm a big believer in reporting failure as well as success; it's important to let others learn from your mistakes. It's embarrassing, but necessary. This is one of those times, I'm afraid. The use of __call() turned out to be a serious problem. Yes, overload() is marked as EXPERIMENTAL in the PHP4 documentation, and brother, do they mean it.

Read on for more information about how __call() bit me in the ass, and why aiming for simultaneous compatibility on PHP4 and PHP5 can be unexpectedly difficult when trying to do "neat stuff."

__call() in PHP4 and PHP5

The first problem is that the arguments for __call() are different in PHP4 and PHP5 and are enforced differently.

In PHP4, you need three arguments: __call($method, $params, &$return). $method is the method called, $params is an array of parameters passed to that method, and &$return is a reference to the variable into which the method call should return a value. The "real" return value of __call() is true (indicating that the call succeeded) or false (which will trigger an error that $method does not exist). You can leave off the &$return parameter if you like, and PHP4 will not complain.

In PHP5, you need exactly two arguments: __call($method, $params), both of which act the same as in PHP4. If you have a third argument, PHP5 will issue a parsing error (which means the script will not load). Under PHP5, the return value of __call() is passed the way you would expect with a normal method, which is why you don't need the &$return argument.

You can see already why this would cause trouble: any __call() definition that works in PHP5 will limit its PHP4 equivalent to never giving a return value (because you can't have the &$return argument in PHP5). Similarly, any fully-functional PHP4 __call() method cannot possibly work under PHP5 (because the &$return argument will cause the PHP5 parser o choke).

__call() in PHP4.3.2 and 4.3.8

When I originally tested the __call() method in 4.3.2, it would successfully set &$return to an object. However, in 4.3.8, it would not set &$return to an object (scalar or array came back OK, but no objects).

Possible Solutions

First, I tried having alternate class definitions in the same file, and picking the definition based on phpversion(). Did not work. PHP5 chokes when parsing the file with a "bad" __call() definition, even if its inside the PHP4 portion of the if() block.

Then I tried extending a base _Savant2 class into Savant2 class proper with an include at the end of the Savant2.php file; that is, if ($php4) include 'Savant2v4.php'; if ($php5) include 'Savant2v5.php'. Each of the version-specific files worked in their respective environments, and I thought I had a successful solution.

However, further testing showed that PHP 4.3.8 would not set &$return to an object (necessary in Savant as it reports plugin errors using the Savant2_Error class). To my recollection, it had worked properly in 4.3.2.

For me, this was the final straw; if __call() didn't work consistently even under 0.0.1 versions of PHP4, then it was not good for production use.

Whose Fault?

Mine, of course. First, I used overload() which is clearly marked as experimental. Then, I tested it thoroughly, but on only one version of PHP (4.3.2) and figured it would be forwards compatible (wrong!). These two errors, combined, resulted in a broken release under some versions of PHP. My goal for Savant is that it run everywhere, and this release failed to meet that goal; to boot, it broke severely under PHP5, which userbase is only growing.

I tried to fix the release, but I fear there is no elegant solution. Rather than excuse my bad planning through documentation (i.e., "Savant works this way under PHP4 but it's not quite right, and under PHP5 it works this other way, so look out!") I decided to pull the release. It's only been out 24 hours, and the added functionality is convenient, not critical. (Still embarrassing and irresponsible to have released it like that in the first place, though.)

So the blame lies with me; I'm sorry if I broke your app with this release. Having said that, oh how I wish the __call() method was identical in both PHP4 and PHP5.



Savant version 2.3.0 now available

I just released Savant version 2.3.0.

Normally, if you want to use a template plugin, you call the plugin() method like so:

<?php $this->plugin('myPlug', $arg1, $arg2); ?>

Through the magic of the overload() function in PHP and the __call() magic method, you can call plugins as if they were native Savant2 methods.

<?php $this->myPlug($arg1, $arg2); ?>

This should make for a little less typing and a little easier reading. For example, to generate a form with Savant2 using the 'form' plugin, you can now do something like this:

<?php
//
// start the form
$this->form('start');
//
// add a text field and label
$this->form('text', 'myTextField', 'default value',
    'Text field label:');
//
// add save and reset buttons as a group
$this->form('group', 'start', 'Group label:');
$this->form('submit', 'op', 'Save');
$this->form('reset', 'op', 'Reset');
$this->form('group', 'end');
//
// end the form
$this->form('end');
?>

(Indicentally, the 'form' plugin is pretty powerful; it support all standard field elements, handles layout, and generates valid XHTML with divs, labels, fieldsets, and tables. Check out the documentation for the 'form' plugin here.)

Savant is an object-oriented template system for PHP. Savant does not compile templates; instead, you write your templates as regular PHP scripts, so there's no new markup to learn. As such, Savant is a simple, elegant, and powerful alternative to Smarty.

UPDATE: (19:24 central time) There appears to be a problem with PHP5 and the __call() method in Savant 2.3.0. Users of PHP will want to test before using 2.3.0. I am working on a patch so that __call() works in Savant2 for both PHP4 and PHP5 transparently, and will blog about the solution at that time. Thanks for your patience.


Yawp 1.0.4 Released, and Yawp2

With this release, sessions can be configured to not auto-start by adding a [Yawp] group 'session_start = false' directive and commenting out the [Auth] group, per request by David Glenn. Download the new version from phpyawp.com.

Also, I'm beginning work on Yawp2, which should be infinitely more configurable using a plugin architecture (suggested via proof-of-concept code from Ian Eure). Instead of being limited to the standard Yawp object set (Auth, Benchmark_Timer, Cache_Lite, DB, Log, and Var_Dump) you will be able to plug in any PEAR object and lazy-load it on first call, as well as autoload objects at Yawp::start() time (the current behavior). There will be support for convenience methods through the core Yawp object so that you can use method calls to a plugin without having to load the plugin yourself.

The idea behind Yawp is that you always need a certain set of single objects in your app: a database connection, a cache, authentication, a logger, and so on. Yawp instantiates, aggregates, and encapsulates those objects away from the global space so you can concentrate on the "real" part of your program. Does that mean Yawp is an example of aspect-oriented programming?


Savant 2.2.0 released

I just released Savant2 version 2.2.0; you can get it from phpsavant.com. Here are two of the changes:

* There is a new error handling class for PHP5 exceptions. When you call setError('exception'), Savant2 will throw a Savant2_Exception whenever there is an error (with the error code and message, of course). This is in addition to setError('pear') for PEAR_Error support, and setError('stack') for PEAR_ErrorStack support.

* By default, Savant does not compile templates. However, there are some cases where you don't want to provide your template designers with full PHP access; as such Savant2 has had support for external compilers. As an example, I have included a new Savant2_Compiler_basic class to show how to create a simple compiler for Savant2.

You can see the updated documentation here.

Savant is a lightweight object-oriented template system for PHP; I bill is as "the simple, elegant, and powerful alternative to Smarty."


Tolerating violence in schools

Walter Williams has something to say about school violence toleration. Here are the final parargraph:

I say it's cruel and unreasonable to permit school thugs to make schools unsafe and education impossible for everyone else. Short of measures to immediately end school violence, parents at the minimum should be able to transfer their children out of unsafe failing public schools. Or, do you believe, as the education establishment does, that parents and children should be held hostage until they come up with a solution?

I love that last line, "...do you believe, as the education establishment does, that parents and children should be held hostage until they [the education establishment] come up with a solution?" I think the same phrasing, i.e. "being held hostage", applies to the whole public system.

When a school's administration is failing, they whine that they need more money and favors, and that the children can't be allowed to go anywhere else because that would jeopardize the school itself; that is nothing more than hostage-taking for the benefit of the administrators and the organization. I say the **children** are the important part of that situation, not the government education system -- let the parents save their kids from failing schools with vouchers.


Nationalized Legal Care

In response to the idea that the Gummint should nationalize "health care" (it's really "medical care" but nobody ever says it that way) we have a great bit from code: theWebSocket; about how we need to nationalize legal care.

We could set it up like this: A new governmental organization, call it the Legal Security Administration, would be formed and paid for through payroll taxes. Lawyers will be given a set amount of money by the LSA to provide legal services for their clients. They will be rewarded when they bring a case in under budget by being able to keep whatever is left over from the preset reimbursement, and take the loss when they fail. These fees will be 60 cents on the dollar of what it costs to provide the services. Lawyers will initally complain that they can't make money at fees paid, but they will be told to just make it up in case volume. Those fee levels will be the basis for what they charge their private-pay clients, and price gouging will be severely punished.

Read the whole thing.


Bill Cosby and Education

Bill Cosby is one of my favorite people ever. He's up there with Ben Stein. Cosby has been in the news this year and last for being a hardass about black kids raising themselves up out of poverty and despair through education, not by claiming victimhood. He continues to speak about it.

Mr. Cosby toured four schools with former Gov. L. Douglas Wilder, who is running for mayor. But instead of talking politics, Mr. Cosby stuck to his no-nonsense message to inner-city black children that at times has made him the target of criticism.

"Study. That's all. It's not tough. You're not picking cotton. You're not picking up the trash. You're not washing windows. You sit down. You read. You develop your brain," Mr. Cosby said at Fred D. Thompson Middle School, where 65 percent of the 700 students meet low-income criteria for free or reduced-price lunches.

Not only is he funny when he wants to be, but he is dead-on right when he speaking about a serious and critical matter. He puts his money and his time where his mouth is, too. Wonderfulness. :-)


Poor Sick Zoe

Primary Dog Zoe is violently ill. She seems to have a bout of ruinous puking and diarrhea every 3-4 months since I've had her (Sep/Oct 2003). This time I think it's my fault, though.

On Friday, I had the occasion to grill up some porterhouse steaks. I kept the bones in the refrigerator, and on Sunday roasted them over the grill, then simmered them for two hours to make stock. After that, I gave one bone to each of the dogs; that was Sunday night about 10pm. They consumed the bones, plus the remaining meat and fat, and seemed OK for it.

But Monday night about 8pm, Zoe was quivering and quiet, obviously unhappy but not "saying" anything. I took her out, and massive poop ensued -- two sets, the second more volumiunous than the first. But then she seemed fine; she perked back up, started playing again. I went to bed about 11:30 and put the dogs in their kennels (lately I keep Backup Dog Wendy in her kennel overnight because she likes to start nipping at Primary Dog and me around 4:30 am, but if she's caged then she just stays asleep -- I keep Primary Dog in kennel then so Backup has company). About 2:30, Backup Wendy starts whining; after about two minutes I yell "No!" and go back to sleep; by 3:30 she's doing it again, so I go out to investigate, and poor Zoe has puked and shat in her kennel. I feel pretty guilty; I think it was the steak bone, too rich for her, that caused her grief. :-(

So now I've finished rinsing and bleaching the kennel pan, the pillow is in the wash, and Primary Dog is outside. Next thing to do is give her a bath and get all that junk off her. No bed, no sleep; no no no, bed bed bed, for Paul until the dogs are OK.


BusinessPundit and Bush

I think this article from BusinessPundit sums up my thoughts about Bush quite nicely.

I am no fan of Bush. I support stem-cell research, which he doesn't. I was against the prescription drug bill, the steel tariffs, the campaign finance reform bill, and the farm subsidy bill. While I don't think Bush is stupid, I don't think he is sharp enough to be President either. But could I vote for Kerry? I don't think so. To me it has come down to voting for the "tax and spend" Democrats or the "cut taxes and spend" Republicans. Does anyone care about shrinking the size of government? Nope. Does anyone care about introducing accountability into the public school system so that Americans don't fall behind the rest of the world? Not really (though they will both pay lip-service to it). So to me it basically boils down to the war on terror, which means as of now, Bush will get my reluctant vote.