FlexLoader __autoload
Door Christiaan Baartse, 20 jaar geleden, 4.414x bekeken
Gewoon de onderstaande code in een file plakken, bijvoorbeeld flexloader.php
In je index flexloader.php includen en vrolijk je classes instatieren zonder je zorgen te maken waar ze staan!
Meer info over wat autoload precies doet is hier te vinden http://php.net/autoload
Opmerkingen zijn welkom!
Gesponsorde koppelingen
PHP script bestanden
Er zijn 19 reacties op 'Flexloader autoload'
Gesponsorde koppelingen
In feite hetzelfde als de autoload functie van het Zend_Framework. Wat overigens heel fijn werkt!
Zend/Loader.php
Zend/Loader.php
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
<?php
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to [email protected] so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Loader
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Loader.php 8064 2008-02-16 10:58:39Z thomas $
*/
/**
* Static methods for loading classes and files.
*
* @category Zend
* @package Zend_Loader
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Loader
{
/**
* Loads a class from a PHP file. The filename must be formatted
* as "$class.php".
*
* If $dirs is a string or an array, it will search the directories
* in the order supplied, and attempt to load the first matching file.
*
* If $dirs is null, it will split the class name at underscores to
* generate a path hierarchy (e.g., "Zend_Example_Class" will map
* to "Zend/Example/Class.php").
*
* If the file was not found in the $dirs, or if no $dirs were specified,
* it will attempt to load it from PHP's include_path.
*
* @param string $class - The full class name of a Zend component.
* @param string|array $dirs - OPTIONAL Either a path or an array of paths
* to search.
* @return void
* @throws Zend_Exception
*/
public static function loadClass($class, $dirs = null)
{
if (class_exists($class, false) || interface_exists($class, false)) {
return;
}
if ((null !== $dirs) && !is_string($dirs) && !is_array($dirs)) {
require_once 'Zend/Exception.php';
throw new Zend_Exception('Directory argument must be a string or an array');
}
// autodiscover the path from the class name
$file = str_replace('_', DIRECTORY_SEPARATOR, $class) . '.php';
if (!empty($dirs)) {
// use the autodiscovered path
$dirPath = dirname($file);
if (is_string($dirs)) {
$dirs = explode(PATH_SEPARATOR, $dirs);
}
foreach ($dirs as $key => $dir) {
if ($dir == '.') {
$dirs[$key] = $dirPath;
} else {
$dir = rtrim($dir, '\\/');
$dirs[$key] = $dir . DIRECTORY_SEPARATOR . $dirPath;
}
}
$file = basename($file);
self::loadFile($file, $dirs, true);
} else {
self::_securityCheck($file);
include_once $file;
}
if (!class_exists($class, false) && !interface_exists($class, false)) {
require_once 'Zend/Exception.php';
throw new Zend_Exception("File \"$file\" was loaded but class \"$class\" was not found in the file");
}
}
/**
* Loads a PHP file. This is a wrapper for PHP's include() function.
*
* $filename must be the complete filename, including any
* extension such as ".php". Note that a security check is performed that
* does not permit extended characters in the filename. This method is
* intended for loading Zend Framework files.
*
* If $dirs is a string or an array, it will search the directories
* in the order supplied, and attempt to load the first matching file.
*
* If the file was not found in the $dirs, or if no $dirs were specified,
* it will attempt to load it from PHP's include_path.
*
* If $once is TRUE, it will use include_once() instead of include().
*
* @param string $filename
* @param string|array $dirs - OPTIONAL either a path or array of paths
* to search.
* @param boolean $once
* @return boolean
* @throws Zend_Exception
*/
public static function loadFile($filename, $dirs = null, $once = false)
{
self::_securityCheck($filename);
/**
* Search in provided directories, as well as include_path
*/
$incPath = false;
if (!empty($dirs) && (is_array($dirs) || is_string($dirs))) {
if (is_array($dirs)) {
$dirs = implode(PATH_SEPARATOR, $dirs);
}
$incPath = get_include_path();
set_include_path($dirs . PATH_SEPARATOR . $incPath);
}
/**
* Try finding for the plain filename in the include_path.
*/
if ($once) {
include_once $filename;
} else {
include $filename;
}
/**
* If searching in directories, reset include_path
*/
if ($incPath) {
set_include_path($incPath);
}
return true;
}
/**
* Returns TRUE if the $filename is readable, or FALSE otherwise.
* This function uses the PHP include_path, where PHP's is_readable()
* does not.
*
* @param string $filename
* @return boolean
*/
public static function isReadable($filename)
{
if (!$fh = @fopen($filename, 'r', true)) {
return false;
}
return true;
}
/**
* spl_autoload() suitable implementation for supporting class autoloading.
*
* Attach to spl_autoload() using the following:
* <code>
* spl_autoload_register(array('Zend_Loader', 'autoload'));
* </code>
*
* @param string $class
* @return string|false Class name on success; false on failure
*/
public static function autoload($class)
{
try {
self::loadClass($class);
return $class;
} catch (Exception $e) {
return false;
}
}
/**
* Register {@link autoload()} with spl_autoload()
*
* @param string $class (optional)
* @param boolean $enabled (optional)
* @return void
* @throws Zend_Exception if spl_autoload() is not found
* or if the specified class does not have an autoload() method.
*/
public static function registerAutoload($class = 'Zend_Loader', $enabled = true)
{
if (!function_exists('spl_autoload_register')) {
require_once 'Zend/Exception.php';
throw new Zend_Exception('spl_autoload does not exist in this PHP installation');
}
self::loadClass($class);
$methods = get_class_methods($class);
if (!in_array('autoload', (array) $methods)) {
require_once 'Zend/Exception.php';
throw new Zend_Exception("The class \"$class\" does not have an autoload() method");
}
if ($enabled === true) {
spl_autoload_register(array($class, 'autoload'));
} else {
spl_autoload_unregister(array($class, 'autoload'));
}
}
/**
* Ensure that filename does not contain exploits
*
* @param string $filename
* @return void
* @throws Zend_Exception
*/
protected static function _securityCheck($filename)
{
/**
* Security check
*/
if (preg_match('/[^a-z0-9\\/\\\\_.-]/i', $filename)) {
require_once 'Zend/Exception.php';
throw new Zend_Exception('Security check: Illegal character in filename');
}
}
/**
* Attempt to include() the file.
*
* include() is not prefixed with the @ operator because if
* the file is loaded and contains a parse error, execution
* will halt silently and this is difficult to debug.
*
* Always set display_errors = Off on production servers!
*
* @param string $filespec
* @param boolean $once
* @return boolean
* @deprecated Since 1.5.0; use loadFile() instead
*/
protected static function _includeFile($filespec, $once = false)
{
if ($once) {
return include_once $filespec;
} else {
return include $filespec ;
}
}
}
[/code]
/**
* Zend Framework
*
* LICENSE
*
* This source file is subject to the new BSD license that is bundled
* with this package in the file LICENSE.txt.
* It is also available through the world-wide-web at this URL:
* http://framework.zend.com/license/new-bsd
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to [email protected] so we can send you a copy immediately.
*
* @category Zend
* @package Zend_Loader
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
* @version $Id: Loader.php 8064 2008-02-16 10:58:39Z thomas $
*/
/**
* Static methods for loading classes and files.
*
* @category Zend
* @package Zend_Loader
* @copyright Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
class Zend_Loader
{
/**
* Loads a class from a PHP file. The filename must be formatted
* as "$class.php".
*
* If $dirs is a string or an array, it will search the directories
* in the order supplied, and attempt to load the first matching file.
*
* If $dirs is null, it will split the class name at underscores to
* generate a path hierarchy (e.g., "Zend_Example_Class" will map
* to "Zend/Example/Class.php").
*
* If the file was not found in the $dirs, or if no $dirs were specified,
* it will attempt to load it from PHP's include_path.
*
* @param string $class - The full class name of a Zend component.
* @param string|array $dirs - OPTIONAL Either a path or an array of paths
* to search.
* @return void
* @throws Zend_Exception
*/
public static function loadClass($class, $dirs = null)
{
if (class_exists($class, false) || interface_exists($class, false)) {
return;
}
if ((null !== $dirs) && !is_string($dirs) && !is_array($dirs)) {
require_once 'Zend/Exception.php';
throw new Zend_Exception('Directory argument must be a string or an array');
}
// autodiscover the path from the class name
$file = str_replace('_', DIRECTORY_SEPARATOR, $class) . '.php';
if (!empty($dirs)) {
// use the autodiscovered path
$dirPath = dirname($file);
if (is_string($dirs)) {
$dirs = explode(PATH_SEPARATOR, $dirs);
}
foreach ($dirs as $key => $dir) {
if ($dir == '.') {
$dirs[$key] = $dirPath;
} else {
$dir = rtrim($dir, '\\/');
$dirs[$key] = $dir . DIRECTORY_SEPARATOR . $dirPath;
}
}
$file = basename($file);
self::loadFile($file, $dirs, true);
} else {
self::_securityCheck($file);
include_once $file;
}
if (!class_exists($class, false) && !interface_exists($class, false)) {
require_once 'Zend/Exception.php';
throw new Zend_Exception("File \"$file\" was loaded but class \"$class\" was not found in the file");
}
}
/**
* Loads a PHP file. This is a wrapper for PHP's include() function.
*
* $filename must be the complete filename, including any
* extension such as ".php". Note that a security check is performed that
* does not permit extended characters in the filename. This method is
* intended for loading Zend Framework files.
*
* If $dirs is a string or an array, it will search the directories
* in the order supplied, and attempt to load the first matching file.
*
* If the file was not found in the $dirs, or if no $dirs were specified,
* it will attempt to load it from PHP's include_path.
*
* If $once is TRUE, it will use include_once() instead of include().
*
* @param string $filename
* @param string|array $dirs - OPTIONAL either a path or array of paths
* to search.
* @param boolean $once
* @return boolean
* @throws Zend_Exception
*/
public static function loadFile($filename, $dirs = null, $once = false)
{
self::_securityCheck($filename);
/**
* Search in provided directories, as well as include_path
*/
$incPath = false;
if (!empty($dirs) && (is_array($dirs) || is_string($dirs))) {
if (is_array($dirs)) {
$dirs = implode(PATH_SEPARATOR, $dirs);
}
$incPath = get_include_path();
set_include_path($dirs . PATH_SEPARATOR . $incPath);
}
/**
* Try finding for the plain filename in the include_path.
*/
if ($once) {
include_once $filename;
} else {
include $filename;
}
/**
* If searching in directories, reset include_path
*/
if ($incPath) {
set_include_path($incPath);
}
return true;
}
/**
* Returns TRUE if the $filename is readable, or FALSE otherwise.
* This function uses the PHP include_path, where PHP's is_readable()
* does not.
*
* @param string $filename
* @return boolean
*/
public static function isReadable($filename)
{
if (!$fh = @fopen($filename, 'r', true)) {
return false;
}
return true;
}
/**
* spl_autoload() suitable implementation for supporting class autoloading.
*
* Attach to spl_autoload() using the following:
* <code>
* spl_autoload_register(array('Zend_Loader', 'autoload'));
* </code>
*
* @param string $class
* @return string|false Class name on success; false on failure
*/
public static function autoload($class)
{
try {
self::loadClass($class);
return $class;
} catch (Exception $e) {
return false;
}
}
/**
* Register {@link autoload()} with spl_autoload()
*
* @param string $class (optional)
* @param boolean $enabled (optional)
* @return void
* @throws Zend_Exception if spl_autoload() is not found
* or if the specified class does not have an autoload() method.
*/
public static function registerAutoload($class = 'Zend_Loader', $enabled = true)
{
if (!function_exists('spl_autoload_register')) {
require_once 'Zend/Exception.php';
throw new Zend_Exception('spl_autoload does not exist in this PHP installation');
}
self::loadClass($class);
$methods = get_class_methods($class);
if (!in_array('autoload', (array) $methods)) {
require_once 'Zend/Exception.php';
throw new Zend_Exception("The class \"$class\" does not have an autoload() method");
}
if ($enabled === true) {
spl_autoload_register(array($class, 'autoload'));
} else {
spl_autoload_unregister(array($class, 'autoload'));
}
}
/**
* Ensure that filename does not contain exploits
*
* @param string $filename
* @return void
* @throws Zend_Exception
*/
protected static function _securityCheck($filename)
{
/**
* Security check
*/
if (preg_match('/[^a-z0-9\\/\\\\_.-]/i', $filename)) {
require_once 'Zend/Exception.php';
throw new Zend_Exception('Security check: Illegal character in filename');
}
}
/**
* Attempt to include() the file.
*
* include() is not prefixed with the @ operator because if
* the file is loaded and contains a parse error, execution
* will halt silently and this is difficult to debug.
*
* Always set display_errors = Off on production servers!
*
* @param string $filespec
* @param boolean $once
* @return boolean
* @deprecated Since 1.5.0; use loadFile() instead
*/
protected static function _includeFile($filespec, $once = false)
{
if ($once) {
return include_once $filespec;
} else {
return include $filespec ;
}
}
}
[/code]
Quote:
Christiaan
@Jonathan: Zodat je dus niet door je include/require header errors krijgt omdat er al whitespace naar de output is verstuurt.
Ik denk dat jullie beide hetzelfde bedoelen, en dat is inderdaad de reden waarom ik mijn class files nooit afsluit met ?>
@Jonathan: Zodat je dus niet door je include/require header errors krijgt omdat er al whitespace naar de output is verstuurt.
Ik denk dat jullie beide hetzelfde bedoelen, en dat is inderdaad de reden waarom ik mijn class files nooit afsluit met ?>
Dat is inderdaad wat ik bedoelde.
Het voordeel? Dat lijkt me duidelijk!
Je hebt al snel veel classes de geladen moeten worden.
Als je in de productie fase zit zal de structuur niet meer veranderen van de locaties. Dus dan kan je deze net zo goed opslaan.
De file iteraties zijn het probleem niet, maar preg_ e.d. zijn t.o.v. een cache bestand wel zwaarder.
Dus door het op te slaan in een bestand kan je dan sneller autoloaden.
Ik heb een singleton methode hiervoor. Deze class kan exporteren naar array.
En vandaar uit kan ik 'm makkelijk wegschrijven naar ini, xml, php, sql...
Maar de lijst wordt niet vaker dan noodzakelijk geladen in de ontwikkel fase.
Maar scheelt nog aanzienliek met caching.
Je hebt al snel veel classes de geladen moeten worden.
Als je in de productie fase zit zal de structuur niet meer veranderen van de locaties. Dus dan kan je deze net zo goed opslaan.
De file iteraties zijn het probleem niet, maar preg_ e.d. zijn t.o.v. een cache bestand wel zwaarder.
Dus door het op te slaan in een bestand kan je dan sneller autoloaden.
Ik heb een singleton methode hiervoor. Deze class kan exporteren naar array.
En vandaar uit kan ik 'm makkelijk wegschrijven naar ini, xml, php, sql...
Maar de lijst wordt niet vaker dan noodzakelijk geladen in de ontwikkel fase.
Maar scheelt nog aanzienliek met caching.
Maar het cache-gebeuren is alleen nodig omdat hij niet de bestandspaden op basis van de klassenamen bepaald. Daarom heeft Zend's autoloader hier geen voordeel bij, de paden van de bestanden zijn direct afhankelijk van de naam. En voor de rest include_path :)
Voordeel van deze implementatie is dat je meerdere klassen per bestand kan hebben, en ze worden allemaal gevonden. Ook kan je helemaal wilt gaan met je directory structuur, waar bij Zend dit enorme klassenamen zou opleveren. "Nadeel" is dat je op die manier zelf moet gaan onthouden waar in welk bestand welke klasse zit.
Voordeel van deze implementatie is dat je meerdere klassen per bestand kan hebben, en ze worden allemaal gevonden. Ook kan je helemaal wilt gaan met je directory structuur, waar bij Zend dit enorme klassenamen zou opleveren. "Nadeel" is dat je op die manier zelf moet gaan onthouden waar in welk bestand welke klasse zit.
@Jelmer
Nog een toevoeging van een nadeel, je code-editor zoals Zend Studio weet geen raad meer met je klasse namen en welke klasse hij nu moet gaan gebruiken om je code te hinten. Dit is de voornaamste reden waarom ik geen auto_load zal implementeren in mijn applicaties. Ik verkies mijn code hinting boven die fractie van een milliseconde dat mijn applicatie sneller wordt. En laat mij maar dan mijn files requiren, weet ik zeker dat ik de goede klasse voor handen heb.
Nog een toevoeging van een nadeel, je code-editor zoals Zend Studio weet geen raad meer met je klasse namen en welke klasse hij nu moet gaan gebruiken om je code te hinten. Dit is de voornaamste reden waarom ik geen auto_load zal implementeren in mijn applicaties. Ik verkies mijn code hinting boven die fractie van een milliseconde dat mijn applicatie sneller wordt. En laat mij maar dan mijn files requiren, weet ik zeker dat ik de goede klasse voor handen heb.
Eclipse (en dus ook de nieuwe Zend Neon) gebruikt alle code uit een project om je hints te geven, en kijkt niet naar de include & require aanroepen.
En autoload is ook niet sneller. In theorie is het zelfs langzamer, omdat iedere keer wanneer een klasse wordt gevonden er eerst moet worden gecontroleerd of hij al is geladen (of hij is gedefinieerd), zo niet, dan moet autoload worden aangeroepen en uitgevoerd (wordt gedaan door class_exists). Vervolgens wordt er weer gekeken of hij is gedefinieerd (ja, class_exists wordt 2 maal aangeroepen, de 2e maal met false als 2e argument) Is het dan nog niet goed, dan volgt een foutmelding. Ook kan ik me voorstellen dat opcaches problemen hebben met de indirecte include aanroepen, al zal hier wel al een oplossing voor zijn, of snel voor komen.
En autoload is ook niet sneller. In theorie is het zelfs langzamer, omdat iedere keer wanneer een klasse wordt gevonden er eerst moet worden gecontroleerd of hij al is geladen (of hij is gedefinieerd), zo niet, dan moet autoload worden aangeroepen en uitgevoerd (wordt gedaan door class_exists). Vervolgens wordt er weer gekeken of hij is gedefinieerd (ja, class_exists wordt 2 maal aangeroepen, de 2e maal met false als 2e argument) Is het dan nog niet goed, dan volgt een foutmelding. Ook kan ik me voorstellen dat opcaches problemen hebben met de indirecte include aanroepen, al zal hier wel al een oplossing voor zijn, of snel voor komen.
@jelmer
Ok mijn excuses ik heb al wel een paar keer gewerkt met Zend Neon, ik ben alleen nog niet overgestapt omdat ik hem nog niet naar al mijn voorkeuren heb kunnen instellen. Ik weet dat Zend Studio iig niet met de auto_load functie overweg kon. Ik was wat bevooroordeeld en trok te vroeg conclusies, mijn excuses.
Ok mijn excuses ik heb al wel een paar keer gewerkt met Zend Neon, ik ben alleen nog niet overgestapt omdat ik hem nog niet naar al mijn voorkeuren heb kunnen instellen. Ik weet dat Zend Studio iig niet met de auto_load functie overweg kon. Ik was wat bevooroordeeld en trok te vroeg conclusies, mijn excuses.
@Jelmer "Voordeel van deze implementatie is dat je meerdere klassen per bestand kan hebben, en ze worden allemaal gevonden. Ook kan je helemaal wilt gaan met je directory structuur, waar bij Zend dit enorme klassenamen zou opleveren. "Nadeel" is dat je op die manier zelf moet gaan onthouden waar in welk bestand welke klasse zit."
Dit is exact de reden waarom ik het op deze manier gedaan heb.
Deze implementatie is veel flexibeler, en kan volgens mij met bijna alle situaties om gaan. (vandaar ook de Flex ;))
Zowieso houd ik niet van underscores in mijn classnamen.
Voor dat onthouden waar de classes staan heb ik Eclipse PDT die mij dat binnen een halve seconde weet te vertellen! :D
Nog inhoudelijke suggesties? Of mensen die het al gebruiken? (ook altijd leuk om te weten)
Dit is exact de reden waarom ik het op deze manier gedaan heb.
Deze implementatie is veel flexibeler, en kan volgens mij met bijna alle situaties om gaan. (vandaar ook de Flex ;))
Zowieso houd ik niet van underscores in mijn classnamen.
Voor dat onthouden waar de classes staan heb ik Eclipse PDT die mij dat binnen een halve seconde weet te vertellen! :D
Nog inhoudelijke suggesties? Of mensen die het al gebruiken? (ook altijd leuk om te weten)
Om te reageren heb je een account nodig en je moet ingelogd zijn.
Inhoudsopgave
Labels
- Geen tags toegevoegd.
PHP hulp
0 seconden vanaf nu