From explosm.net
from C&H explosm.net

For the past  year one of my side-not-so-side projects has been the zen\this Framework. Technically the project is even older than that. It was started because many years ago I wrote a Database library for MySQL that I really liked. It wrapped mysql/mysqli into what I consider a much more common and better interface. At the time it was designed to be portable to any codebase and handle things like injection protection without me or the other developers (who were at the time, interns) spacing about it. When I decided to write additional libraries the design challenge was to mimic the original design pattern of that database library.

The interface was quite simple. The main database class was a series of static functions, and there was a query object class too. This was before we had namespaces in PHP so the main database class was really just being used as a namespace. Configuration options were placed in a static array, database::$config, and most of the functions referenced that when deciding which database to query as it handled multiple connections.  This worked great as a completely stand alone library but after it evolved into the current edition in zen\this there have been some design issues.

Design Challenge: Configuration

Keeping the database configuration in a static array on the library works very well. The issue is that in a framework as many of the libraries as possible need the ability to be optional. If we start a new project using the framework that does not need database connectivity, or some of our API’s do not need database while others do, we should be able to skip loading the database library all together. This is easily done, however the design challenge was if the database library is not loaded, then the lines in the config file that reference static variable will kill the application as they will be undefined.

This lead to the development of a core framework options API, where instead of saying something like this in the config file:

PHP Code:
<?php

zen
\database::$config = array(
    
'main' => array(
        
'host' => 'localhost',
        
'user' => 'magic',
        
'pass' => 'beans',
        
'db' => 'storytime'
    
),
    
'other' => array( ... )
);

?>

we would do something like this:

PHP Code:
<?php

zen
\this::setOption('zen_database_config',array(
    
'main' => array(
        
'host' => 'localhost',
        
'user' => 'magic',
        
'pass' => 'beans',
        
'db' => 'storytime'
    
),
    
'other' => array( ... )
));

?>

This way, if the database is undefined (e.g. not loaded) our application will not crash in that instance due to undefined classes. The secondary benefit is if we change our mind later and load the database library after-the-fact, the config is still there. If nothing but the bare essentials of the framework are currently loaded, the settings API will exist and allow the application to proceed without special handling like having to wrap everything with if(class_exists()) { }.

The benefits from a global settings management have rippled down through the entire framework, and as of now I am still in the progress of migrating all the libraries to use it. Among the additional benefits, a big one has been having the ability to define default values easily if no specific ones have been provided by the user configuration file.

Design Challenge: Developer API

Another design issue from when this library was standalone was the developer API, and by that I mean how do we as the programmer use it. Originally it was half procedural (using static methods on the database class) and half object oriented (using the query object returned by static methods) and this did not fit with the full OOP feeling of the rest of the framework as it was evolving.

Somewhere though there still has to be a singleton instance of something, somewhere to store active connections and configurations. The database class still has the static config array and it still has a static pointer array for holding open connections, but it has been migrated to a fully OOP interface. Where something like this with the original library:

PHP Code:
<?php

zen
\database::connect('default');

$result zen\database::queryf('SELECT ...','default');
while(
$row $result->next()) {
    
// ...
}

?>

has evolved into this:

PHP Code:
<?php

$db 
= new zen\database('default');

$result $db->queryf('SELECT ...');
while(
$row $result->next()) {
    
// ...
}

?>

Both methods do the same thing, both connect to the specified database (default) if it is not already connected, both query the default database, and both return a query object. The difference is only in the API, and if you smash your script enough, you will find some difference in performance. In this instance with the way PHP is currently with namespaces and static methods, the OOP method will actually perform slightly better (however not noticeably).

More benefits from the OOP version is that we could have two instances of the same database, which would use the same database connection but allow a different set of features. For example we could set one instance to buffer queries and another instance to not buffer queries. With the original API we would have to flip the buffer option back and forth every time instead if just having it. That example is not entirely useful but it paints the picture.

Handling multiple databases also became much more clear in the resulting project code. Take this example of a theoretical porting of an old database to a new database:

PHP Code:
<?php

$old 
= new zen\database('old-database');
$new = new zen\database('new-database');

$result $old->queryf('SELECT ...');
while(
$row $result->next()) {
    
$new->queryf('INSERT ...');
}

?>

It is important to note that when we create a new instance of the database, we are not connecting to it every time and disconnecting from it when we unset it or let it fall out of scope. It will reuse any open database connections that already exist throughout the entire instance of that application session. That is how it keeps its performance check.

Design Challenge: Consistency

One of the biggest challenges I find when bringing together multiple libraries that I have done over time and proven to be solid is making all their interfaces consistent with each other. If they are not refactored to be alike, then the framework as a whole is just a pile of parts and not a fluid system. This is an issue that covers the entire scope of development and if not handled with care can ruin the project and your morale.

If you are laughing that I am considering your personal mental well being as an important part of project consistency, you may not have enough experience with large projects yet. If you take a “screw it” approach to a problem later down the road you may find that solution a massive flaming problem of flames. If you do not want to work with your own code why would anyone else?

Your future with your own code

The biggest scary of evolving your projects is when you have to go back and work on an old project using an old version. Chances are you will want to upgrade it to use some new feature you added later. Your choices would be to upgrade it, deal with it, or never add new features or change how they work. You should never be afraid to change how a feature in your system works if the change is for the better. Having to update older projects is almost always less work than having to deal with missing or bad features that you fixed later on, even if it sounds hell boring. That was the moral of this story – cheers.