Recently I've been creating a lot of small PHP libs/modules that I would like to be able to reuses in other projects. Issues always come about when I need to include the files from other modules and how to keep them path independent and organized without wrapping everything into a parent namespace. Namespaces, autoloaders, and a bootloader has been the best solution I've come up with until now.
So for example, I have a message queue module (group of classes) which I keep in a directory /hacklabs/modules/mq/. Everything in this directory is namespaced in 'mq', for example the class "queue" ( /hacklabs/modules/mq/queue.php ):
namespace mq;
class queue {
# ...
}
/hacklabs/modules/mq/exceptions/empty_queue_exception.php:
namespace mq\exceptions;
class empty_queue_exception {
# ...
}
In another project, I would like to use this mq module. Now comes the bootloader of the mq module ( /hacklabs/modules/mq/bootloader.php )
define('MQ_PATH', dirname(__FILE__));
# add the parent directory to the include path:
set_include_path( get_include_path() . PATH_SEPARATOR . realpath( dirname( __FILE__ ) . '/../' ) );
spl_autoload_register();
At this point, if I want to use the module 'mq' from a project in /hacklabs/projects/big_project/ all I need to do is include the bootloader from my modules and the default spl autoloader will take care of the rest:
namespace big_project;
require_once('/hacklabs/modules/mq/bootloader.php');
# also load a forums module bootloader:
require_once('/hacklabs/modules/forums/bootloader.php');
$queue = new \mq\queue();
$msg = new \mq\message();
try {
$queue->send( $msg );
} catch ( \mq\exceptions\empty_queue_exception $e ) {
# ...
} catch ( \exception $e ) {
# ...
}
$forum = new \forums\forum();
# ...
Using this technique, I can make module specific defines in the modules bootloader while the actual autoload include path is anything in /hacklabs/modules/*.
Include just the modules bootloader, then the rest is handled via spl_autoload_register() and namespaced code.