/www/slight

To get this branch, use:
bzr branch http://bzr.ed.am/www/slight
1 by Tim Marston
initial commit
1
<?php
2
/**
3
 * Flight: An extensible micro-framework.
4
 *
5
 * @copyright   Copyright (c) 2011, Mike Cao <mike@mikecao.com>
6
 * @license     MIT, http://flightphp.com/license
7
 */
8
9
namespace flight\core;
10
11
/**
12
 * The Loader class is responsible for loading objects. It maintains
13
 * a list of reusable class instances and can generate a new class
14
 * instances with custom initialization parameters. It also performs
15
 * class autoloading.
16
 */
17
class Loader {
18
    /**
19
     * Registered classes.
20
     *
21
     * @var array
22
     */
23
    protected $classes = array();
24
25
    /**
26
     * Class instances.
27
     *
28
     * @var array
29
     */
30
    protected $instances = array();
31
32
    /**
33
     * Autoload directories.
34
     *
35
     * @var array
36
     */
37
    protected static $dirs = array();
38
39
    /**
40
     * Registers a class.
41
     *
42
     * @param string $name Registry name
43
     * @param string|callable $class Class name or function to instantiate class
44
     * @param array $params Class initialization parameters
45
     * @param callback $callback Function to call after object instantiation
46
     */
47
    public function register($name, $class, array $params = array(), $callback = null) {
48
        unset($this->instances[$name]);
49
50
        $this->classes[$name] = array($class, $params, $callback);
51
    }
52
53
    /**
54
     * Unregisters a class.
55
     *
56
     * @param string $name Registry name
57
     */
58
    public function unregister($name) {
59
        unset($this->classes[$name]);
60
    }
61
62
    /**
63
     * Loads a registered class.
64
     *
65
     * @param string $name Method name
66
     * @param bool $shared Shared instance
67
     * @return object Class instance
68
     */
69
    public function load($name, $shared = true) {
70
        $obj = null;
71
72
        if (isset($this->classes[$name])) {
73
            list($class, $params, $callback) = $this->classes[$name];
74
75
            $exists = isset($this->instances[$name]);
76
77
            if ($shared) {
78
                $obj = ($exists) ?
79
                    $this->getInstance($name) :
80
                    $this->newInstance($class, $params);
81
                
82
                if (!$exists) {
83
                    $this->instances[$name] = $obj;
84
                }
85
            }
86
            else {
87
                $obj = $this->newInstance($class, $params);
88
            }
89
90
            if ($callback && (!$shared || !$exists)) {
91
                $ref = array(&$obj);
92
                call_user_func_array($callback, $ref);
93
            }
94
        }
95
96
        return $obj;
97
    }
98
99
    /**
100
     * Gets a single instance of a class.
101
     *
102
     * @param string $name Instance name
103
     * @return object Class instance
104
     */
105
    public function getInstance($name) {
106
        return isset($this->instances[$name]) ? $this->instances[$name] : null;
107
    }
108
109
    /**
110
     * Gets a new instance of a class.
111
     *
112
     * @param string|callable $class Class name or callback function to instantiate class
113
     * @param array $params Class initialization parameters
114
     * @return object Class instance
115
     */
116
    public function newInstance($class, array $params = array()) {
117
        if (is_callable($class)) {
118
            return call_user_func_array($class, $params);
119
        }
120
121
        switch (count($params)) {
122
            case 0:
123
                return new $class();
124
            case 1:
125
                return new $class($params[0]);
126
            case 2:
127
                return new $class($params[0], $params[1]);
128
            case 3:
129
                return new $class($params[0], $params[1], $params[2]);
130
            case 4:
131
                return new $class($params[0], $params[1], $params[2], $params[3]);
132
            case 5:
133
                return new $class($params[0], $params[1], $params[2], $params[3], $params[4]);
134
            default:
135
                $refClass = new \ReflectionClass($class);
136
                return $refClass->newInstanceArgs($params);
137
        }
138
    }
139
140
    /**
141
     * Resets the object to the initial state.
142
     */
143
    public function reset() {
144
        $this->classes = array();
145
        $this->instances = array();
146
    }
147
148
    /*** Autoloading Functions ***/
149
150
    /**
151
     * Starts/stops autoloader.
152
     *
153
     * @param bool $enabled Enable/disable autoloading
154
     * @param mixed $dirs Autoload directories
155
     */
156
    public static function autoload($enabled = true, $dirs = array()) {
157
        if ($enabled) {
158
            spl_autoload_register(array(__CLASS__, 'loadClass'));
159
        }
160
        else {
161
            spl_autoload_unregister(array(__CLASS__, 'loadClass'));
162
        }
163
164
        if (!empty($dirs)) {
165
            self::addDirectory($dirs);
166
        }
167
    }
168
169
    /**
170
     * Autoloads classes.
171
     *
172
     * @param string $class Class name
173
     */
174
    public static function loadClass($class) {
175
        $class_file = str_replace(array('\\', '_'), '/', $class).'.php';
176
177
        foreach (self::$dirs as $dir) {
178
            $file = $dir.'/'.$class_file;
179
            if (file_exists($file)) {
180
                require $file;
181
                return;
182
            }
183
        }
184
    }
185
186
    /**
187
     * Adds a directory for autoloading classes.
188
     *
189
     * @param mixed $dir Directory path
190
     */
191
    public static function addDirectory($dir) {
192
        if (is_array($dir) || is_object($dir)) {
193
            foreach ($dir as $value) {
194
                self::addDirectory($value);
195
            }
196
        }
197
        else if (is_string($dir)) {
198
            if (!in_array($dir, self::$dirs)) self::$dirs[] = $dir;
199
        }
200
    }
201
}