I'm trying to build my own framework for internal usage. I got structure like this:
index.php
boot /
booter.php
application /
controllers /
indexcontroller.php
core /
template.class.php
model.class.php
controller.class.php
cache /
memcached.php
something /
something.php
Booter.php contains: (it's currently working only with files located in core directory):
class Booter
{
private static $controller_path, $model_path, $class_path;
public static function setDirs($controller_path = 'application/controllers', $model_path = 'application/models', $classes_path = 'core')
{
self::$controller_path = $controller_path;
self::$model_path = $model_path;
self::$class_path = $classes_path;
spl_autoload_register(array('Booter', 'LoadClass'));
if ( DEBUG )
Debugger::log('Setting dirs...');
}
protected static function LoadClass($className)
{
$className = strtolower($className);
if ( file_exists(DIR . '/' . self::$model_path . '/' . $className . '.php') )
{
require(DIR . '/' . self::$model_path . '/' . $className . '.php');
}
else if ( file_exists(DIR . '/' . self::$class_path . '/' . $className . '.class.php') )
{
require(DIR . '/' . self::$class_path . '/' . $className . '.class.php');
}
else if ( file_exists(DIR . '/' . self::$controller_path . '/' . $className . '.php') )
{
require(DIR . '/' . self::$controller_path . '/' . $className . '.php');
}
if ( DEBUG )
Debugger::log('AutoLoading classname: '.$className);
}
}
My application/controllers/indexcontroller looks like this:
<?
class IndexController extends Controller
{
public function ActionIndex()
{
$a = new Model; // It works
$a = new Controller; //It works too
}
}
?>
And here comes my questions:
[Question 1]
My code is working currently like this:
$a = new Model; // Class Model gets included from core/model.class.php
How I can implement including files by classes with namespaces? For example:
$a = new Cache\Memcached; // I would like to include file from /core/CACHE/Memcached.php
$a = new AnotherNS\smth; // i would like to include file from /core/AnotherNS/smth.php
and so on. How I can produce the handling of the namespace?
[Question 2]
Is it a good practice to use single autoload for Classes, Controllers and models or I should define 3 different spl_autoload_register with 3 different methods and why?
Question 1:
In your autoloader, change the \ (for the namespace) into DIRECTORY_SEPARATOR
. This should work:
protected static function LoadClass($className)
{
$className = strtolower($className);
$className = str_replace('\\', DIRECTORY_SEPARATOR, $className);
...
}
Always use DIRECTORY_SEPARATOR
, especially if the software has the potential to be used on other platforms.
Question 2:
I would use one and separate your classes by namespace. However, I think that comes down to how you want to structure your framework and how you separate your code. Someone else may be able to better answer that question.
I normally have a bootstrap.php
file inside a folder conf
that is in the application root. My code is normally located inside an src
folder, also located in the root, so, this works fine for me:
<?php
define('APP_ROOT', dirname(__DIR__) . DIRECTORY_SEPARATOR);
set_include_path(
implode(PATH_SEPARATOR,
array_unique(
array_merge(
array(
APP_ROOT . 'src',
APP_ROOT . 'test'
),
explode(PATH_SEPARATOR, get_include_path())
)
)
)
);
spl_autoload_register(function ($class) {
$file = sprintf("%s.php", str_replace('\\', DIRECTORY_SEPARATOR, $class));
if (($classPath = stream_resolve_include_path($file)) != false) {
require $classPath;
}
}, true);
You can generalize this into your "Booter" class and append directories to the include path. If you have well defined namespace names, there will be no problems with colisions.
Edit: This works if you follow PSR-1.