Paul M. Jones

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

DB_Table goes "beta" in new 0.22.0 release

I just released DB_Table 0.22.0 beta. This is the first new release since July 7, and the first beta release. It has been pretty well tested against MySQL and PostgreSQL, but should work with Oracle, MS-SQL, and SQLite as well. I'd be very happy if MS-SQL or Oracle users could provide feedback on how well DB_Table works on those systems; please email me if you would like to provide a report.

The ideas behind DB_Table are simple: embed your column definitions and baseline queries within the PHP class. Then you can call select('myQuery') and get your results, or call insert($myColumns) to insert a new row, and so on. Becuase the class knows the column definitions, it can validate the new data before even connecting to the database; you can extend the validation method to cover all kinds of data. This also lets you automatically create a form based on the column definitions with HTML_QuickForm. DB_Table automates table creation; if a table does not exist in the database when you call a DB_Table object, DB_Table can create it right then, along with indexes -- all because the column definitions are embedded in the class.

DB_Table also provides a poor-man's version of data type abstraction. This element is somewhat controversial. We all know that different database systems keep date and time data in different formats, and it becomes an ... interesting ... task to create portable SQL statements that will work properly against those different systems. Metabase and its cousin MDB do this by providing translation functions to convert the native RDBMS format to a common format on retrieval and insert/update, but they are not exactly fully automated.

The DB_Table abstraction method (such as it is) instead forces the database to store the date and time as fixed-length strings in ISO-standard format. While this is going to give most database administrators a case of the screaming rants, it is a very workable solution for low- and mid-range applications where portability, not 100% optimization and efficiency among multiple systems, is the paramount concern. This is particularly good for those of us who write applications intended for distribution and need to know for sure that the app will work on a wide range of databases (with minimal effort). For example, YaWiki uses DB_Table to great effect.

You can read the full DB_Table documentation here.


Belmont Club

Wretchard at Belmont Club is a great writer and analyst. Read this post right away.

It is interesting to compare Marine preparations to assault Fallujah in April 2004 with those apparently under way today, just months later. The Marine methods of April would have been instantly familiar to any military historian: hammer and anvil, seizure of key terrain; feint and attack. Today, many of the military objectives in the developing siege of the terrorist stronghold are abstract. They consist of developing a network of informers in the city; of setting up a functioning wireless network; of getting close enough for smaller US units to deploy their line-of-sight controlled UAV and UGV units to create a seamless operational and tactical environment to wage "swarm" warfare; of getting artillery and mortar units close enough to play hopscotch over everything the network decides to engage. To the traditional methods of warfare the Americans were adding a whole new plane which only they could inhabit.

It looks like large organizations can adopt strategies to beat a small, dispersed, loosely connected foe. Thank goodness the leadership had the willingness to let go of traditional tactics and lear new ones on-the-fly.


Adam Smith and Charles Darwin

This brief entry from Cafe Hayek about the Scottish Enlightenment is, ah, enlightening, especially when read in the context of emergent behaviors.

About Stewart's intellectual biography of Adam Smith, Gould has this to say: "[Darwin] imbibed the basic belief of the Scottish economists that theories of overall social structure must begin by analyzing the unconstrained actions of individuals ... The theory of natural selection is a creative transfer to biology of Adam Smith's basic argument for a rational economy: the balance and order of nature does not arise from a higher, external (divine) control, or from the existence of laws operating directly upon the whole, but from struggle among individuals for their own benefits."

Read the whole thing; it's short and sweet. (I know a family of Scots, and let me tell you, the intelligence and creative thinking displayed by Smith and Adams has not dwindled over the intervening generations.)


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.