Monday, January 25. 2010
vfsStream 0.5.0 released
Today I shipped vfsStream 0.5.0 which brings a new feature thanks to the efforts of Benoit Aubuchon: vfsStream now supports the rename() functionality which allows you to write test cases using vfsStream for methods that rename files. Another patch of him was to change the stat() call to respect the STREAM_URL_STAT_QUIET flag.
One more new feature is the added support for . as current directory alias so that vfs://foo/. resolves to vfs://foo - this allows to use file_exists($dir . '/.') as workaround for the failing is_executable() call on directories, as described in the comments to the is_executable() documentation in the PHP manual. Of course this raises the question if vfsStream will support .. as well - if somebody takes the time to create a patch I will incorporate this. I did not look into this issue further, but I guess it might involve recursion and a more advanced parsing of the vfs URL to make it work properly, as there might be cases like vfs://foo/bar/baz/../../dummy. So grab the release and make use of the new features, if you like to. ![]() Friday, January 8. 2010
Delayed logging in Stubbles 1.1.0 and API breaks
Today I want to present a new feature we will introduce with Stubbles 1.1.0: delayed logging. Stubbles already offers a simple to use but powerful logging API, so what can we achieve with this new feature and how to use it?
But first I want to take a look at how log data is generated and written. If you want to log something you first call $logger->createLogEntry('aTarget) which gives you an instance of LogEntry. Depending on the log entry factory which is actually used to create the instance this LogEntry instance might already be prefilled with some data, e.g. the session id, a timestamp and so on and so forth. After that you fill this instance with the data you actually want to log by using its addData() method, and finally calling log() to get it written to a logfile, a database or whatever appender you use. Now, what happens if you want to log data but when some data utilized by the log entry factory is not available at this point? An example might be the startup phase of your application, where some of the log data depends on calculations done in a later step, but you have to log some data from the current step which in turn is a prerequisite for the later step. Until now this was only possible using ugly workarounds and hacks - and if you are using Stubbles one thing is for sure: you neither like workarounds nor hacks. Stubbles 1.1.0 and delayed logging to the rescue: we extended the log entry class with a new logDelayed() method which will take care the logger knows about this log entry, but does not hand it over to the log appenders yet. Instead, the logger keeps the log entry in memory, and waits until someone calls it's processDelayedLogEntries() method, or (more likely) the logger instance gets destroyed. If this happens it asks the log entry factory to recreate the log entry in question before handing it to the log appenders, and this gives the log entry factory the chance to replace any earlier not available data with the current version before the log entry is finally written. Sounds good? Well, as all great stuff this comes with a price. The log entry factory interface had to be extended, so if you upgrade your application you have to change your log entry factory implementation as well: either provide an own implementation of the new recreate() method or extend the abstract log entry factory class introduced with 1.1.0 which provides a default implemention. Why this API break? We had two options: either provide a new interface or do the API break. Introducing a new interface would have saved us from the API break, but would be more effort to test and implement, harder to document and understand by (future) users and leading to more complications in the future as well. On the other hand, this is a minor release where API breaks are allowed. Keeping backward compatibility only to be friendly is nothing we should aim at as the API break would be have to be done somewhere in the future anyway, by deprecating the old interface. As users tend to delay API upgrades whenever they can it is better to force them to do it as early as possible. ![]() Wednesday, January 6. 2010
Interceptors and dependency injection
Interceptors in Stubbles allow to intercept (yeah...) the request before the actual processor is called (PreInterceptor) and after the processor has done it's work to create the response (PostInterceptor) but before this response is sent back to the user agent. This is quite powerful and allows manipulating the request before any real work is done as well as manipulating the response before it is sent. Usage examples range from setting up the correct variant for the website depending on request parameters or cookies up to turning the response from a default 200 OK into a 304 Not Modified status.
Until now creation of interceptors and their dependencies was quite limited as they were configured via XJConf and not with Stubbles' own IoC framework which means there was no proper way to get an interceptors' dependencies injected. It was only possible by using the stubBinderRegistry as a kind of service locator, which means to actively look for things instead of just ask for them as explicit dependencies via constructor and/or setter method parameters. Fortunately, this is going to change with Stubbles 1.1.0. Stubbles 1.1.0 introduces a new interceptor initializer based on a property file. The property file contains a list of both pre- and postinterceptor class names, and this new interceptor initializer will iterate through this list and create every interceptor instance using Stubbles IoC, allowing you to make full usage of Stubbles IoC features in your interceptor class. No more looking for things which makes your interceptors hard to test, but just explicitly asking for dependencies. What about the old way? Stubbles 1.1.x will still support the old way using xml configuration files and XJConf without Stubbles IoC, but you have to activate it explicitly when upgrading. To do this, put a call to stubWebsiteBindingModule::usingInterceporInitializer( 'net::stubbles::ipo::interceptors::stubInterceptorXJConfInitializer') in your index.php file (please note that this is not a static method call, but a method call on an instance of stubWebsiteBindingModule). However, we encourage to upgrade to the new behaviour, as it is more powerful and much cleaner. The old way becomes deprecated with 1.1.0 and will be removed with 1.2.0 or 2.0.0 (whichever comes first, we don't know yet). ![]() Monday, January 4. 2010
Registry Design Pattern - useful or harmful?
About a year ago I wrote about How to get a Singleton right. While nothing has changed my opinion about the Singleton Design Pattern - contrary, I'm even more convinced that it is bad, bad and bad - I still have homework to do. In the comments to this article I was asked about my opinion on the Registry Design Pattern, and I promised it would be worth an own blog entry. Well, I did not anticipate it would take more than a year to write it, but you know, work, and no time, and yada yada yada... so here it is.
When thinking about a Registry one has to consider two points: overall architecture of the application, and implementation of the Registry itself. It's not that much what you can say about the implementation of a Registry. For PHP, it should just follow one rule to make it testable and to ease testing of classes using the registry: do not make it a Singleton. (You might have guessed that already.) PHP offers the possibility to implement the Registry as a pure static class, where data within the Registry can be stored within a static class variable, and setters as well as getters can also be static methods. There is no value in making it a Singleton, it just more stuff to type where the result is the same: global state. So if you implement it as pure static, the Registry in itself is neither bad or good. Speaking of global state, it should be common sense by now that global state is a bad idea, at least if this global does not mean the root of the application itself, which leads us to the overall architecture of the application. How is this related to the Registry Design Pattern? The Registry is intended to allow access to configuration data, objects etc. which you don't want to pass around in your application but require them in different parts (or layers) of your applications. If you have such a need from my point of view this means the application is not fully based on the Dependency Injection principle, it does not separate object creation and business logic as much as it should. If the application is completely based on Dependency Injection, there is no need for a Registry any more. Did I just say that there is no need for a Registry any more? Well, two exceptions. First, unfortunately in PHP there might be cases where you can not influence the creation of an object instance, and if you want to pass data or other objects to such an instance, you have to take cumbersome actions to pass those. Creation of user land stream wrapper instances is such an example, as those instances are created by PHP itself and there is no possibility to intercept this. Here a Registry might be of help, but it stays what it is: a workaround for a flaw in PHP. The other exception is the case of using a Dependency Injection framework. You do not need a Registry here - your DI framework already has something like this. It just not called Registry, but it is it's mechanism where you bind data or objects for example in the case of Stubbles or Google Guice, and in Symfony it is called Service Container. (Please note that this is just a quick thought I had in the last days, I might be wrong on this.) To conclude, the Registry itself is neither useful or harmful. The more important question is how strong you apply the Dependency Injection principle in your application. ![]() ![]() |
![]() ![]() Calendar
![]() Archives![]() Categories![]() Quicksearch![]() Blogs we read...![]() Syndicate This Blog![]() Blog Administration![]() ![]() |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||




