Solar 0.8.0 Released

(UPDATE: Fixed the broken link to Solar. Thanks, Justin Patrin.)

After *entirely* too long, I’ve packaged and released Solar version 0.8.0 (devel). I had wanted to release it two weeks ago, but other events demanded priority.

There are lots of changes, so be sure to read the change notes before upgrading. One thing to pay attention to in particular is that I’ve updated the bundled Savant3 installation to beta 2, and updated the Savant3_Plugin_Form installation to 0.2.1 (dev). You can read the various Savant3 change notes at the Savant site.

You’ll find the 0.8.0 release notes for Solar below; be warned, it’s quite long.

Continue reading

Benchmarking call_user_func_array()

Andreas Korthaus wrote the Savant mailing list recently with some interesting benchmark numbers on Savant3 and the output escaping routines. He wrote up a quick template script (in PHP of course) and used the Savant eprint() method 300+ times to escape output (which itself uses only htmlspecialchars() by default). Then he ran the script; the time to run was …

Result: 161 ms

After that I looked at the cachegrind listings to find out
where some noticable time is lost. Looks like escaping costs a
lot of time, so I changed my templates not to use output
escaping:

Result: 12 ms!!!

No, I did not forget a digit 😉

So it seems the way escaping is implemented, hurts performance
very much!

That very dramatic difference in running times (14x!) looked mostly due to the fact that he wasn’t using htmlspecialchars() on the echoed output. Then he changed all the “echo” to “echo htmlspecialchars()” and claimed only a 1.5ms difference. Followup emails from his continued benchmarking noted the slow-points in Savant were related primarily to call_user_func_array() calling the escaping functions, although the output escaping itself also adds running time.

All this piqued my interest to see the speed difference between using native functions, user-defined functions, objects, variable-functions, and the call_user_func[_array]() functions. For an experiment, I wrote a user-defined function …

// mimics htmlentities() as a user-defined function
function html($value)
{
	return htmlentities($value);
}

… and a user-defined class:

class example {
	// mimics htmlentites() as a method
	function html($value)
	{
		return htmlentities($value);
	}
}

Then I wrote a script to make 100,000 calls to each of these:

  • htmlentities($value)
  • html($value)
  • $func($value) where $func = ‘html’
  • $object->html($value) where $object = new example()
  • $object->$func($value)
  • call_user_func($func, $value)
  • call_user_func(array($object, $func), $value)
  • call_user_func_array($func, array($value))
  • call_user_func_array(array($object, $func), array($value))

One set of representative results from my Mac Mini (PHP 5.1rc1), in seconds:

name            : diff     : description
native          : 0.614219 : htmlentities($value)
literal_func    : 0.745537 : html($value)
variable_func   : 0.826048 : $func($value)
literal_method  : 0.957708 : $object->html($value)
variable_method : 0.840837 : $object->$func($value)
call_func       : 1.006599 : call_user_func($func, $value)
call_object     : 1.193323 : call_user_func((array($object, $func), $value)
cufa_func       : 1.232891 : call_user_func_array($func, array($value))
cufa_object     : 1.309725 : call_user_func_array((array($object, $func), array($value)

Here’s another one:

name            : diff     : total
native          : 0.772733 : 0.772733
literal_func    : 0.737210 : 1.509943
variable_func   : 0.807990 : 2.317933
literal_method  : 0.820931 : 3.138864
variable_method : 0.821516 : 3.960380
call_func       : 1.006845 : 4.967225
call_object     : 1.210223 : 6.177448
cufa_func       : 1.114493 : 7.291941
cufa_object     : 1.307970 : 8.599911

And another, just for good measure:

name            : diff     : total
native          : 0.613295 : 0.613295
literal_func    : 0.733299 : 1.346594
variable_func   : 0.815782 : 2.162376
literal_method  : 0.965143 : 3.127519
variable_method : 0.842771 : 3.970290
call_func       : 1.023640 : 4.993930
call_object     : 1.221747 : 6.215677
cufa_func       : 1.104610 : 7.320287
cufa_object     : 1.449468 : 8.769755

So native calls to htmlentities() are twice as fast as doing effectively the same thing via call_user_func() with an object method, and using call_user_func_array() is 10-20% slower than using call_user_func(). I hadn’t realized the differences in speed of execution would be so distinct; of course, I never really thought about it before, either. Clearly PHP has to do a lot more work behind the scenes to map the variables to objects and parameters when using call_user_func_array().

You can download the very simple func_speed.php script here.

Um, you’ll need Solar for it (sorry about that, I used the debug-timer object for the testing).

Stumping for Solar

Joe Stump writes a good MVC overview at OnLamp.com in this article. He’s kind enough to mention my Solar project in one of the opening paragraphs:

As of this writing, there are very few true MVC frameworks written in PHP. In fact, there is only one that I know of, Solar, that is entirely pure PHP 5 code. Another one out there is Cake, which is trying to be the “Ruby on Rails of PHP.” I, personally, have a few problems with both of these frameworks. Both Solar and Cake fail to leverage existing code in PEAR, Smarty, etc. Cake appears a bit disorganized at the moment. Finally, Solar is the work of mostly a single person (not that Paul isn’t a great coder or person, but there is only a single gatekeeper at the time of this writing). These may not be issues that concern you, and if they don’t concern you, by all means check these two out.

I’m thankful for the mention, but I want to nitpick a bit. 😉

That Solar does not use PEAR: Solar does not use PEAR code, because most PEAR code (especially for the parts that Solar needs) are not E_STRICT compliant for PHP5. Because Solar aims for strict PHP5, reuse is not really an option.

Regarding Smarty reuse: Solar uses the Savant3 template system instead of Smarty. Of course, I wrote Savant too, so this may not count so much in Joe’s eyes. 😉

That Solar is the work of one person: Well, this part is true in the way he means it; I’m the founder, and pretty much the only author on the project (see below for caveats). I take a lot of direction and input from Solar users and commenters, but only insofar as their opinions match the foundational concepts of Solar to begin with.

The benefit of the “one person” model, at least in the beginning, is that the project has evidence of conceptual integrity (as outlined by Fred Brooks in The Mythical Man Month).

The drawback is that one person can only do so much work over time. If other people want to help, I’m all for it. However, my experience has been that it takes people a long time to contribute new features to a project, usually (1) after they have used and picked it apart over an extended period, and (2) when it has solved other problems for them, but fails to solve an additional related problem. (Bug reports are a different beast. 😉

Solar, as a public project, has only been around since February 2005. Six months of an in-development project is not really long enough for major contributions to arrive en masse (9 to 12 is usually more like it). I’m very happy for the help I have received so far, though:

  • Clay hosts the site and acts as sounding board
  • Matthew authored Solar_Filter and Solar_Form_Load_Xml
  • Jean-Eric is the first translation contributor
  • Travis as the “loyal opposition” to simplicity and brevity 😉
  • Everyone else on mailing list 🙂

[UPDATE] When I say above that Solar doesn’t reuse PEAR code, I mean the libraries. Solar is installed and upgraded using the PEAR installer, and is distributed via a PEAR channel. The entire PHP world has Greg Beaver to thank for recent and spectacular developments on that front. 🙂

Savant3 version 3.0.0 beta 2

On the heels of yesterday’s Savant2 release, I have a Savant3 beta 2 release today; you can view the change log on the main page. With any luck, this will be the last beta release of Savant3; if I get no bug reports, I’ll mark it stable (at last!).

In addition, I’ve been working on the newly separated Form plugin package; look for a release of that in the next few days, with .phpt-based unit tests included.

And then I get to start documentation on everything. 🙂