如何php 类的自动加载类

8179人阅读
J2EE(12)
有时候在开发web应用的时候,需要tomcat启动后自动加载一个用户的类,执行一些初始化方法,如从数据库中加载业务字典到内存中,因此需要在tomcat启动时就自动加载一个类,或运行一个类的方法。
可以采用在WEB-INF/web.xml中添加一个监听程序(ServletContextListener配置项),步骤如下:1) 增加一个监听程序 MyServletContextListener.java, 实现javax.servlet.ServletContextListener接口package test.
import javax.servlet.ServletContextEimport javax.servlet.ServletContextL
public class MyServletContextListener implements ServletContextListener {
public void contextDestroyed(ServletContextEvent arg0) {
public void contextInitialized(ServletContextEvent arg0) {System.out.println("加载业务字典");try {mon.dict.DictMap.loadData();}catch(Exception e) {System.out.println("加载业务字典失败!");e.printStackTrace();}}}
2) 配置监听器web.xml:
&listener&&listener-class&test.startup.MyServletContextListener&/listener-class&&/listener&
注意:应用事件监听器程序是建立或修改servlet环境或会话对象时通知的类。它们是servlet规范的版本2.3中的新内容。注册一个监听程序涉及在 web.xml的web-app元素内放置一个listener元素。虽然listener元素的结构很简单,但请不要忘记,必须正确地给出web- app元素内的子元素的次序。listener元素位于所有的servlet 元素之前以及所有filter-mapping元素之后。此外,因为应用生存期监听程序是serlvet规范的2.3版本中的新内容,所以必须使用 web.xml DTD的2.3或以后版本,而不是2.2版本,如下:&web-app id="WebApp_ID" version="2.4"xmlns=""xmlns:xsi=""xsi:schemaLocation=" "&...&/web-app&
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:323012次
积分:4370
积分:4370
排名:第6622名
原创:113篇
转载:42篇
评论:17条
(1)(1)(1)(1)(12)(1)(1)(4)(8)(8)(4)(4)(1)(6)(1)(2)(1)(1)(4)(2)(11)(1)(8)(1)(1)(24)(48)如何在tomcat启动时自动加载一个类 以便初始化程序
如何在tomcat启动时自动加载一个类 以便初始化程序
编辑:www.fx114.net
本篇文章主要介绍了"如何在tomcat启动时自动加载一个类 以便初始化程序",主要涉及到如何在tomcat启动时自动加载一个类 以便初始化程序方面的内容,对于如何在tomcat启动时自动加载一个类 以便初始化程序感兴趣的同学可以参考一下。
如何在tomcat启动时自动加载一个类&以便初始化程序
有时候在开发web应用的时候,需要tomcat启动后自动加载一个用户的类,执行一些初始化方法,如从数据库中加载业务字典到内存中,因此需要在tomcat启动时就自动加载一个类,或运行一个类的方法。
可以采用在WEB-INF/web.xml中添加一个监听程序(ServletContextListener配置项),步骤如下:
1) 增加一个监听程序 MyServletContextListener.java,实现javax.servlet.ServletContextListener接口
package test.
import javax.servlet.ServletContextE
import javax.servlet.ServletContextL
public class MyServletContextListener implementsServletContextListener {
public void contextDestroyed(ServletContextEvent arg0) {
public void contextInitialized(ServletContextEvent arg0) {
System.out.println(&加载业务字典&);
mon.dict.DictMap.loadData();
}catch(Exception e) {
System.out.println(&加载业务字典失败!&);
e.printStackTrace();
2) 配置监听器web.xml:
&listener&
&listener-class&test.startup.MyServletContextListener&/listener-class&
&/listener&
注意:应用事件监听器程序是建立或修改servlet环境或会话对象时通知的类。它们是servlet规范的版本2.3中的新内容。注册一个监听程序涉及在web.xml的web-app元素内放置一个listener元素。虽然listener元素的结构很简单,但请不要忘记,必须正确地给出web-app元素内的子元素的次序。listener元素位于所有的servlet元素之前以及所有filter-mapping元素之后。此外,因为应用生存期监听程序是serlvet规范的2.3版本中的新内容,所以必须使用web.xmlDTD的2.3或以后版本,而不是2.2版本,如下:
&web-app id=&WebApp_ID& version=&2.4&
xmlns=&/xml/ns/j2ee&
xmlns:xsi=&http://www.w3.org/2001/XMLSchema-instance&
xsi:schemaLocation=&/xml/ns/j2ee/xml/ns/j2ee/web-app_2_4.xsd&&
&/web-app&
一、不得利用本站危害国家安全、泄露国家秘密,不得侵犯国家社会集体的和公民的合法权益,不得利用本站制作、复制和传播不法有害信息!
二、互相尊重,对自己的言论和行为负责。
本文标题:
本页链接:小邓博客,一位正在奋斗的PHP开发工程师的学习经历分享!为高效PHP开发而努力奋斗
在学习PHP的面向对象的时候,会知道很多“语法糖”,也就是魔术方法。有一个加自动加载的魔术方法,叫:__autoload();
先看一段代码
function __autoload($classname) {
$filename = &./&. $classname .&.php&;
include_once($filename);
这里实例化了一个A类,但在代码块中没有A类的相关代码,按常理是应该会报错,因为没有找到对应的A类,但如果你使用了autoload()自动加载函数的话,结果就可以能不一样
从上面的流程图:在页面实例化一个新类,就会先在当前目录找对应的类代码,如果没有就去autoload堆栈找对应的自动加载函数,如果有的话就自动加载该类,没有话就抛出错误。
这是PHP自动加载的一个机制。然后重点在后面。如果我有多个自动加载的函数,怎么办!
PHP提供了一个SPL函数
spl_autoload_register(); // 注册autoload函数
官方:spl_autoload_register() 提供了一种更加灵活的方式来实现类的自动加载。因此,不再建议使用 __autoload() 函数,在以后的版本中它可能被弃用。
然而在PHPexecl 和 PHPWord 里面都使用到了 这个函数来做自动加载,但两者有区别!!
PHPexecl 自动加载的方法(这里作者估计是Python工程师,不然花括号都没有,用缩进来表示)
public static function Register() {
$functions = spl_autoload_functions();
foreach ( $functions as
$function)
spl_autoload_unregister($function);
$functions = array_merge(array(array('PHPExcel_Autoloader','Load')),$functions);
foreach ( $functions as $function)
$x = spl_autoload_register($function);
return $x;
PHPWord 自动加载的方法
public static function Register() {
return spl_autoload_register(array('PHPWord_Autoloader', 'Load'));
这两种方法,都可以完成重定义自动加载,但有区别? 如果是独立运行代码,两种情况都可以运行,但要是整合到框架中,比如YII框架。那么PHPWord的自动加载就无效了。
因为YII框架自动带有自动加载函数,而且再代码运行的时候就已经注册了,而spl_autoload_register()会将新的自动加载函数,加载autoload队列的后面。所有PHPWord在运行的时候
就调用的是YII框架定义的自动加载机制,而且不是PHPWord这种加载方式。
所以反过来看PHPexecl的加载函数,你就明白了。
转载请注明: &
or分享 (0)
$(document).ready(function() {
$('.fancybox').fancybox();
$("#submit").click(function(){
var that = $("#Mark");
var val = $.trim(that.val());
if(val.length === 0)
that.css('border-color','red');
$("#note").html('你或多或少要添一点东西吧!不让你中奖了怎么领?');
$(".no").html("asdasdasdasd");
$(".info").hide();
$(".result").show();问题对人有帮助,内容完整,我也想知道答案
问题没有实际价值,缺少关键内容,没有改进余地
┡┈▓ libralies
┊ ┡┈▓ database
┊ ┊ ┡┈▓ driver
┊ ┊ ┊ ┡┈? mysql.php
┊ ┊ ┊ ┡┈? mysqli.php
┊ ┊ ┊ ┗┈? sqlite.php
┊ ┊ ┡┈▓ query
┊ ┊ ┊ ┡┈? mysql.php
┊ ┊ ┊ ┡┈? mysqli.php
┊ ┊ ┊ ┗┈? sqlite.php
┊ ┊ ┡┈? driver.php
┊ ┊ ┗┈? query.php
┊ ┟┈▓ session
┊ ┊ ┟┈▓ storage
┊ ┊ ┊ ┟┈? database.php
┊ ┊ ┊ ┟┈? mamcache.php
┊ ┊ ┊ ┗┈? none.php
┊ ┊ ┗┈? storage.php
┊ ┡┈? database.php
┊ ┡┈? session.php
这样的文件结构,怎样设计一个自动加载类,在实例化类的时候按需加载相的应类
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
建议你看一下 Zend Framework 的设计和 PSR 标准。
Autoloader 的设计可以参考 ZF1 和 ZF2 的 Autoloader 或者 Composer 的 Autoloader。
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
方法1(简单粗暴)
把你想能自动加载的类的目录添加到自动加载目录中
set_include_path('libralies/database/driver' . PATH_SEPARATOR . get_include_path());
方法2(推荐)
根据目录或者命名空间自动加载
function __autoload(){
$dir = './libralies';
set_include_path(get_include_path(). PATH_SEPARATOR. $dir);
$class = str_replace('\\', '/', $class) . '.php';
require_once($class);
这种方法需要你在创建类的时候通过命名空间方式
$a = new Libralies\Databases\Driver\M
__autoload函数会把它转化成相对路径然后导入
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
spl_autoload //php的框架自动加载基本上都是通过这个实现的。
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
这是我在一个项目中的做法:
function core_autoload($class_name) {
$prefix = substr($class_name,0,2);
switch($prefix){
case 'm_':
$file_name = ROOT_PATH . '/app/models/' . substr($class_name, 2) . '.php';
case 'a_':
$file_name = ROOT_PATH . '/app/actions/' . substr($class_name, 2) . '.php';
case 'u_':
$file_name = ROOT_PATH . '/app/lib/usr/' . substr($class_name, 2) . '.php';
$file_name =
get_include_path() . str_replace('_', '/', $class_name).'.php';
if( file_exists($file_name) )
require_once $file_
else spl_autoload($class_name);
spl_autoload_register('core_autoload');
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
自动加载 + 命名空间, 这是几乎所有开源框架所用的方式。
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
建议用命名空间
可以采用 PSR-0 标准
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
建义看下composer的实现
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
composer 就可以实现,为啥还要自己开发?
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
小弟采用的是文件名和类名相同的加载方式!望笑纳
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
使用spl_autoload_register函数注册类加载函数,类名根据路径名以_相隔
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
可以看看symfony的自动类加载,超级赞。退而其次看thinkphp
答案对人有帮助,有参考价值
答案没帮助,是错误的答案,答非所问
相关知识Composer命名空间Psr-0Psr-4
同步到新浪微博
分享到微博?
你好!看起来你挺喜欢这个内容,但是你还没有注册帐号。 当你创建了帐号,我们能准确地追踪你关注的问题,在有新答案或内容的时候收到网页和邮件通知。还能直接向作者咨询更多细节。如果上面的内容有帮助,记得点赞 (????)? 表示感谢。
明天提醒我
关闭理由:
删除理由:
忽略理由:
推广(招聘、广告、SEO 等)方面的内容
与已有问题重复(请编辑该提问指向已有相同问题)
答非所问,不符合答题要求
宜作评论而非答案
带有人身攻击、辱骂、仇恨等违反条款的内容
无法获得确切结果的问题
非开发直接相关的问题
非技术提问的讨论型问题
其他原因(请补充说明)
我要该,理由是:
扫扫下载 AppKeyboard Shortcuts?
Next menu item
Previous menu item
Previous man page
Next man page
Scroll to bottom
Scroll to top
Goto homepage
Goto search(current page)
Focus search box
Change language:
Brazilian Portuguese
Chinese (Simplified)
类的自动加载
在编写面向对象(OOP) 程序时,很多开发者为每个类新建一个 PHP 文件。
这会带来一个烦恼:每个脚本的开头,都需要包含(include)一个长长的列表(每个类都有个文件)。
在 PHP 5 中,已经不再需要这样了。
函数可以注册任意数量的自动加载器,当使用尚未被定义的类(class)和接口(interface)时自动去加载。通过注册自动加载器,脚本引擎在
PHP 出错失败前有了最后一个机会加载所需的类。
函数也能自动加载类和接口,但更建议使用
提供了一种更加灵活的方式来实现类的自动加载(同一个应用中,可以支持任意数量的加载器,比如第三方库中的)。因此,不再建议使用
函数,在以后的版本中它可能被弃用。
在 PHP 5.3 之前,__autoload 函数抛出的异常不能被
语句块捕获并会导致一个致命错误(Fatal Error)。
自 PHP 5.3 起,能够 thrown 自定义的异常(Exception),随后自定义异常类即可使用。
__autoload
函数可以递归的自动加载自定义异常类。
自动加载不可用于 PHP 的 CLI 。
如果类名比如被用于 ,则它可能包含一些危险的字符,比如 ../。
建议您在这样的函数中不要使用用户的输入,起码需要在
时验证下输入。
Example #1 自动加载示例
本例尝试分别从 MyClass1.php
和 MyClass2.php 文件中加载
MyClass1 和
MyClass2 类。
&?phpspl_autoload_register(function&($class_name)&{&&&&require_once&$class_name&.&'.php';});$obj&&=&new&MyClass1();$obj2&=&new&MyClass2();?&
Example #2 另一个例子
本例尝试加载接口 ITest。
&?phpspl_autoload_register(function&($name)&{&&&&var_dump($name);});class&Foo&implements&ITest&{}/*string(5)&"ITest"Fatal&error:&Interface&'ITest'&not&found&in&...*/?&
Example #3 自动加载在 PHP 5.3.0+ 中的异常处理
本例抛出一个异常并在 try/catch 语句块中演示。
&?phpspl_autoload_register(function&($name)&{&&&&echo&"Want&to&load&$name.\n";&&&&throw&new&Exception("Unable&to&load&$name.");});try&{&&&&$obj&=&new&NonLoadableClass();}&catch&(Exception&$e)&{&&&&echo&$e-&getMessage(),&"\n";}?&
以上例程会输出:
Want to load NonLoadableClass.
Unable to load NonLoadableClass.
Example #4 自动加载在 PHP 5.3.0+ 中的异常处理 - 没有自定义异常机制
本例将一个异常抛给不存在的自定义异常处理函数。
&?phpspl_autoload_register(function&($name)&{&&&&echo&"Want&to&load&$name.\n";&&&&throw&new&MissingException("Unable&to&load&$name.");});try&{&&&&$obj&=&new&NonLoadableClass();}&catch&(Exception&$e)&{&&&&echo&$e-&getMessage(),&"\n";}?&
以上例程会输出:
Want to load NonLoadableClass.
Want to load MissingException.
Fatal error: Class 'MissingException' not found in testMissingException.php on line 4
You don't need exceptions to figure out if a class can be autoloaded. This is much simpler.
&?php
function __autoload($className) {
& & & if (file_exists($className . '.php')) {
& & & & & require_once $className . '.php';
& & & & & return true;
& & & }
& & & return false;
}
function canClassBeAutloaded($className) {
& & & return class_exists($className);
}
?&
You should not have to use require_once inside the autoloader, as if the class is not found it wouldn't be trying to look for it by using the autoloader. Just use require(), which will be better on performance as well as it does not have to check if it is unique.
__autoload() function can be very useful to optimize your code esp. when you have so many classes.Unlike class extensions, optional parameters with class restrictions may not load your class.&?phpclass bClass{& function fun($p1, aClass $p2=NULL){& & }}$b = new bClass();$b-&fun('No!');$b-&fun('Really?', new aClass('Yes!'));?&So, it's very encouraging to use classes everywhere!Even encapsulating your functions inside simple classes to use like static modules, will help a lot!Let's say, you have &b&50k&/b& lines of code inside &b&100&/b& classes/files.. If you need a simple task to do very quickly, you should not be loading all of those files, except the ones you need.Though, it may be dangerous on some cases regarding the dependencies, load order, etc. Carefully design your classes.
Andrew: 03-Nov-That seems a bit messy to me, this is a bit neater:&?php& & function __autoload($class_name) & & {& & & & $directorys = array(& & & & & & 'classes/',& & & & & & 'classes/otherclasses/',& & & & & & 'classes2/',& & & & & & 'module1/classes/'& & & & );& & & & & & & & foreach($directorys as $directory)& & & & {& & & & & & if(file_exists($directory.$class_name . '.php'))& & & & & & {& & & & & & & & require_once($directory.$class_name . '.php');& & & & & & & & & & & & & & }& & & & & & & & & & }& & }
In a subclass, I was trying to call an overridden parent method with an arbitrary number of arguments:
&?php
call_user_func_array(array('parent', 'someNonStaticMethod'), $args);
?&
It turns out this triggers an E_STRICT level warning. So I changed to this:
&?php
call_user_func_array(array($this, 'parent::someNonStaticMethod'), $args);
?&
This doesn't trigger any warnings, but it has the undesirable (if not downright buggy) effect of calling my __autoload() function with the argument 'parent'. I had to modify __autoload() to handle this special situation:
&?php
function __autoload($cls)
{
& & if ('parent' != $cls)
& & {
& & & & require("class.$cls.php");
& & }
}
?&
Tested on Linux with PHP 5.1.6 and 5.2.5.
Before you start using __autload, remember that it holds no scope/namespace. This means that if you are depending on third party applications and they have an autoload function defined and so do you, your application will error.To remedy this, everyone should look at the spl_autoload functions, eg: spl_autoload_register. This function allows more than one custom functions to be called through the default spl_autoload (default __autoload) handler.
I'm sure this is needed by more than me.My objective was to allow __autoload() to be easily extended in complex systems/frameworks where specific libraries etc may need loading differently but you don't want to hard-code little adjustments into your working __autoload() to allow this to happen.Using a ServiceLocator object with some static methods and properties to allow loosely coupled locators to be attached to it you can swap/change and add to the functionality of your __autoload() at runtime.The core stuff:&?phpinterface Locator{& & public function canLocate($class);& & public function getPath($class);}class ServiceLocator{& & protected static $locators = array();& & & & public static function attachLocator(Locator $locator, $key)& & {& & & & self::$locators[$key] = $locator;& & }& & public static function dropLocator($key)& & {& & & & if (self::isActiveLocator($key))& & & & {& & & & & & unset(self::$locators[$key]);& & & & & & return true;& & & & }& & & & else return false;& & }& & public static function isActiveLocator($key)& & {& & & & return array_key_exists($key, self::$locators);& & }& & public function load($class)& & {& & & & foreach (self::$locators as $key =& $obj)& & & & {& & & & & & if ($obj-&canLocate($class))& & & & & & {& & & & & & & & require_once $obj-&getPath($class);& & & & & & & & if (class_exists($class))& & & & & & }& & & & }& & }}function __autoload($class){& & $locator = new ServiceLocator();& & $locator-&load($class);}?&An example Use Case:&?phprequire 'ServiceLocator.php';class PearLocator implements Locator{& & protected $base = '.';& & & & public function __construct($directory='.')& & {& & & & $this-&base = (string) $directory;& & }& & & & public function canLocate($class)& & {& & & & $path = $this-&getPath($class);& & & & if (file_exists($path)) return true;& & & & else return false;& & }& & & & public function getPath($class)& & {& & & & return $this-&base . '/' . str_replace('_', '/', $class) . '.php';& & }}ServiceLocator::attachLocator(new PearLocator(), 'PEAR');$foo = new Foo_Test();?&
Be careful when using eval (as always) in __autoload. The following:&?phpecho 'Start-&';function __autoload($class) {& & eval('class ' . $class . ' {};');}$class = 'Class1{}; echo "uh oh"; class Class2';$obj = new $class;echo 'end';?&outputs:Start-&uh ohYou can use preg_replace to clean up $class to prevent executing abitrary code but in this case you won't be able to throw a catchable exception and your script will end with a fatal error.
More simpler example of using spl_autoload_register in 5.3:&?phpspl_autoload_register(function($classname) {& });?&
You can enable this behaviour for undefined classes while unserializing objects by setting the .ini-variable 'unserialize_callback_func' to '__autoload'.
This autoload function searches for the class Location before requiring it. So there's no need of putting the classes all in one folder. Requirements: - the subfolders must be at least 3 letters long - the filenames must be in the form CLASSNAME.class.phpNote: - in this example the main class folder is 'lib'define('ROOT_DIR', dirname(__FILE__).'/');function __autoload($className) {& & $folder=classFolder($className);& & if($folder) require_once($folder.'/'.$className.'.class.php');}function classFolder($className,$folder='lib') {& & $dir=dir(ROOT_DIR.$folder);& & if($folder=='lib' && file_exists(ROOT_DIR.$folder.'/'.$className.'.class.php')) return $& & else {& & & & while (false!==($entry=$dir-&read())) {& & & & & & $checkFolder=$folder.'/'.$& & & & & & if(strlen($entry)&2) {& & & & & & & & if(is_dir(ROOT_DIR.$checkFolder)) {& & & & & & & & & & if(file_exists(ROOT_DIR.$checkFolder.'/'.$className.'.class.php')) return $checkF& & & & & & & & & & else {& & & & & & & & & & & & $subFolder=classFolder($className,$checkFolder);& & & & & & & & & & & & if($subFolder) return $subF& & & & & & & & & & }& & & & & & & & }& & & & & & }& & & & } & & }& & $dir-&close();& & return 0;}
Or you can use this, without using any "require/include":&?phpclass autoloader {& & public static $loader;& & public static function init()& & {& & & & if (self::$loader == NULL)& & & & & & self::$loader = new self();& & & & return self::$loader;& & }& & public function __construct()& & {& & & & spl_autoload_register(array($this,'model'));& & & & spl_autoload_register(array($this,'helper'));& & & & spl_autoload_register(array($this,'controller'));& & & & spl_autoload_register(array($this,'library'));& & }& & public function library($class)& & {& & & & set_include_path(get_include_path().PATH_SEPARATOR.'/lib/');& & & & spl_autoload_extensions('.library.php');& & & & spl_autoload($class);& & }& & public function controller($class)& & {& & & & $class = preg_replace('/_controller$/ui','',$class);& & & & & & & & set_include_path(get_include_path().PATH_SEPARATOR.'/controller/');& & & & spl_autoload_extensions('.controller.php');& & & & spl_autoload($class);& & }& & public function model($class)& & {& & & & $class = preg_replace('/_model$/ui','',$class);& & & & & & & & set_include_path(get_include_path().PATH_SEPARATOR.'/model/');& & & & spl_autoload_extensions('.model.php');& & & & spl_autoload($class);& & }& & public function helper($class)& & {& & & & $class = preg_replace('/_helper$/ui','',$class);& & & & set_include_path(get_include_path().PATH_SEPARATOR.'/helper/');& & & & spl_autoload_extensions('.helper.php');& & & & spl_autoload($class);& & }}autoloader::init();?&
The following function may be useful if you want to simulate namespaces and autoloading behavior:define ("CLASS_ROOT", '/classes/');function __autoload ($className){& & require_once CLASS_ROOT.str_replace('_', '/', $className).'.class.php';}Then you will just have to use the folder structure and name the classes accordingly. If you want to have a class named Page, which will be in the pseudo namespace System.Web.UI, create a directory named System in /classes, then create Web, then UI, then name the class System_Web_UI_Page. Kind of long to type if you don't have autocomplete, but at least you will not have to manage the loading of all the classes' definitions.
Note to Ricos posting:A lot of useless Coding. However, I improved the code, so now it will be able to find any folders ("." and ".." will not being tested... oO) and search as deep as possible. Now it will find CLASS_DIR/foo/bar.class.php also like CLASS_DIR/foo/bar/baz/buz/fii/and/so/on/class.phpWarning: This code will check ALL dirs who're "deeper" / "lower" than the class dir, so prevent deeply hidden files (or use just a few folders).Improved Version:&?phpdefine("CLASS_DIR", dirname(__FILE__));function __autoload($className) {& & $folder = classFolder($className);& & if($folder)& & & & require_once($folder.$className.".class.php");}function classFolder($className, $sub = "/") {& & $dir = dir(CLASS_DIR.$sub);& & & & if(file_exists(CLASS_DIR.$sub.$className.".class.php"))& & & & return CLASS_DIR.$sub;& & while(false !== ($folder = $dir-&read())) {& & & & if($folder != "." && $folder != "..") {& & & & & & if(is_dir(CLASS_DIR.$sub.$folder)) {& & & & & & & & $subFolder = classFolder($className, $sub.$folder."/");& & & & & & & & & & & & & & & & if($subFolder)& & & & & & & & & & return $subFolder;& & & & & & }& & & & }& & }& & $dir-&close();& & return false;}?&
Because static classes have no constructor I use this to initialize such classes.
The function init will (if available) be called when you first use the class.
The class must not be included before, otherwise the init-function wont be called as autoloading is not used.
&?php
function __autoload($class_name)
{
& & require_once(CLASSES_PATH.$class_name.'.cls.php');
& & if(method_exists($class_name,'init'))
& & & & call_user_func(array($class_name,'init'));
& & return true;
}
?&
I use it for example to establish the mysql-connection on demand.
It is also possilbe do add a destructor by adding this lines to the function:
&?php
if(method_exists($class_name,'destruct'))
& & register_shutdown_function(array($class_name,'destruct'));
?&
I found out a neat way to centralize one single class which will give accessibility to other classes.& I also added a parameter to the __construct method which would be an array of classes you want loaded.& This isn't completely necessary, but it will stop "excessive memory" if you're loading a bunch of unused classes.
&?php
class Bot {
& & private $classes = array (
& & & & 'Socket' =& "connection/class.Socket.php",
& & & & 'Input'& =& "io/class.Input.php",
& & & & 'Output' =& "io/class.Output.php",
& & & & 'Parse'& =& "io/parse/class.Parse.php"
& & );
& & public $Socket, $Input, $Output, $Parse; public function __construct($load=false){
& & & & if(is_array($load)){
& & & & & & foreach($load as $class){
& & & & & & & & if(isset($this-&classes[$class])){
& & & & & & & & & & require($this-&classes[$class]);
& & & & & & & & & & $this-&$class = new $class($this);
& & & & & & & & }
& & & & & & }
& & & & } else {
& & & & & & foreach($this-&classes as $class =& $path){
& & & & & & & & require($path);
& & & & & & & & $this-&$class = new $class($this);
& & & & & & }
& & & & }
& & }
}
?&
I just stumbled over one quite nice solution to the __autoload-exception problem.& It allows for any kind of exception to be thrown inside __autoload().It appears one has to define the requested class (using "eval", which is not nice but inevitable here) and after that can simply throw an exception (and catch it if so desired):&?phpfunction __autoload($className){&& if (! $ok) {& & & eval("class $className{};");& & & throw new Exception('My message');&& } }try {&& UndefinedClass::undefinedFunction();} catch (Exception $ex) {&& echo $ex-&getMessage();} ?&Output: "My Message".& :-)
While using an "autoloading" method you should pay attention to variables scope. Because of new file will be included INSIDE of magic function __autoload - all of declared in such file global scope variables will be only available within this function and nowhere else. This will cause strange behaviour in some cases. For example:file bar.class.php:&?php$somedata = 'Some data';& && class bar {& & function __construct()& & & & {& & & & & & global $somedata;& & if ( isset($somedata) )& & & & {& & & & & & var_dump($somedata);& & & & }& & & & else& & & & {& & & & & & die('No data!');& & & & }& & }}?&Attempt to load this file in common way:&?phprequire 'bar.class.php';$foo = new bar();?&this will output (as expected):string(9) "Some data"But in case of __autoload:&?phpfunction __autoload($classname){& & require $classname . '.class.php';}$foo = new bar();?&you could expect that this script will return the same but no, it will return "No data!", because defenition of $somedata after requiring treats as local within user-defined function __autoload().
It's worth to mention, if your operating system is case-sensitive you need to name your file with same case as in source code eg. MyClass.php instead of myclass.php
My idea for autoloading FUNCTIONS however only in a weird way :
&?php
function ex($parms)
{
&& $argvar = func_get_args();
&& $func = $argvar[0];
&& $funcargs = array_slice($argvar,1);
if (function_exists($func))
&& {
&& $returnvalue = call_user_func_array($func,$funcargs);
&& }
else
&& {
&& $funcpath = "scripts/".$func.".php";
&& require_once($funcpath);
&&
&& if (function_exists($func))
& & & {
& & & $returnvalue = call_user_func_array($func,$funcargs);
& & & }&
&& else
& & & {
& & & && die "SORRY& $func IS NOT USABLE";
& & & }
&& }
return $returnvalue;
}
?&
USAGE EXAMPLE:
must be caled using the X function giving the real function as first parameter, like:
$result = ex("add",1,2);
// returns 3 if add function defined in add.php sums the first and second parameter..
Throwing versions of __autoload based on eval will fail if __autoload will be caled with interface name.&?phpclass Cls implements Iface {}; ?&
Just a small autoload class (that works if you use corretly names, namespaces, uses and so on) found elsewhere with a small modification for linux:&?phpfunction __autoload($className)& {& var_dump($className);& $file = str_replace('\\', DIRECTORY_SEPARATOR, $className) . '.php';& var_dump($file);& var_dump(file_exists($file));& if (!file_exists($file)) {& & return false;& }& else {& & require $file;& & return true;& }}?&
do not use is_subclass_of() in your __autoload() function to identify a class type and thereby its path (f.e exceptions). is_subclass_of() needs to know the class, but you want to check BEFORE you include the class.
in response to alexey at renatasystems dot org:You may add ``global $`` before ``$somedata = 'Some data';`` and it should work as expected.file bar.class.php:&?phpglobal $somedata;$somedata = 'Some data';& & class bar {&& function __construct()&& && {&& & & && global $somedata;& & if ( isset($somedata) )& & && {& & & & && var_dump($somedata);& & && }& & && else& & && {& & & & && die('No data!');& & && }&& }}?&'common way':&?phprequire 'bar.class.php';$foo = new bar();?&'__autoload way':&?phpfunction __autoload($classname){&& require $classname . '.class.php';}$foo = new bar();?&Both 'comon way' and '__autoload way' should give same result:string(9) "Some data"
The following might provide a good work-around for throwing exceptions from the __autoload function when a file containing the correct class doesn't exists.function __autoload ($class_name) {& $file = 'system/objects/' . $class_name . '.inc.php';& if (!file_exists ($file)) {& & return eval ("class $class_name {" .& & & & & & & && "& function $class_name () {" .& & & & & & & && "& & throw new Exception ();" .& & & & & & & && "& }" .& & & & & & & && "}");& }& require_once ($file);}Cheers,Nolan
I'm very taken with the autoload function, and thought I would share with you my implementation of it:&?phpfunction __autoload($class_name) {& & $settings = Settings::Load();& & $classes = $settings-&getSettings('classes');& & $path = $classes[$class_name];& & & & if(file_exists($path)) {& & & & require_once($path);& & & & return true;& & } else {& & & & clearstatcache();& & & & $classes = $settings-&ReLoadSettings();& & & & $path = $classes['classes'][$class_name];& & }& & & & & & if(file_exists($path)) {& & & & require_once($path);& & & & return true;& & } else {& & & & die("The requested library,".$class_name.", could not be found at ".$classes[$class_name][$i].". Please check your ini file");& & }}?&
This is my autoloader for my PSR-4 clases. I prefer to use composer's autoloader, but this works for legacy projects that can't use composer.&?phpclass Autoloader{& & public static function register()& & {& & & & spl_autoload_register(function ($class) {& & & & & & $file = str_replace('\\', DIRECTORY_SEPARATOR, $class).'.php';& & & & & & if (file_exists($file)) {& & & & & & & & require $file;& & & & & & & & return true;& & & & & & }& & & & & & return false;& & & & });& & }}Autoloader::register();
PHP 7 new feature.spl_autoload_register(function ($name) {& & echo "Want to load $name.";});new NonLoadableClass();Output like this....Want to load NonLoadableClass.FATAL ERROR Uncaught Error: Class 'NonLoadableClass' not found in /home4/phptest/public_html/code.php70(5) : eval()'d code:8 Stack trace: #0 /home4/phptest/public_html/code.php70(5): eval() #1 {main} thrown on line number 8
On the if/else, you are better off either entering a break after success and continue on else (if you feel as though you have to return something), or otherwise not putting in an else.& the else with return will cause a premature end to the function.Also, if you use an array of directories, it may be a good idea to enter a blank ('') as the first value so that the script will check locally.
My autoloader function:&?phpfunction __autoload( $class_name ){& & $invalidChars = array(& & & & '.', '\\', '/', ':', '*', '?', '"', '&', '&', "'", '|'& & );& & & & $class_name = str_replace($invalidChars, '', $class_name);& & & & $extension_prefix = '.class.php';& & & & if( !@include_once $class_name . $extension_prefix )& & {& & & & $path = 'lib'; foreach( new DirectoryIterator($path) as $file )& & & & {& & & & & & if($file-&isDot()) { }& & & & & & & & & & & & if($file-&isDir())& & & & & & {& & & & & & & & $file = $path . DIRECTORY_SEPARATOR . $file-&getFilename() . DIRECTORY_SEPARATOR . $class_name . $extension_prefix;& & & & & & & & & & & & & & & & & & if(file_exists($file)) {& & & & & & & & & & include_once $file;& & & & & & & & }& & & & & & }& & & & }& & & & }& & if (!class_exists($class_name, false) || !interface_exists($class_name, false)) {& & & & }}?&
Autoloaders & Namespaces: The effective namespace of an autoloaded file must match that of it just& finding and loading the file isn't enough. (I know, seems obvious now, but...)My namespaces may serve as hints to locations within the file system, and I tried to be cute:& && If a class (file) wasn't found where it was expected, my autoloader also looked in an alternate location. This worked fine, except that the alternate's own qualified namespace was thus slightly different (reflecting where *it* lived). So although the desired class was ultimately loaded (name and all), the original caller's reference remained unsatisfied because of the namespace discrepancy (as it should, really), but it was subtle.Of course, this scheme works fine within the same namespace (explicit or not).And kudos to the autoload devs for anticipating what could have been an endless autoload loop.
The tip to use spl_autoload_register() instead of __autoload() should be taken seriously. It seems that __autoload() doesn't always get called when calling an unloaded class within a class, eg:&?phpclass MyClass {& & public static function doStuff() {& & & & $a = MyOtherClass::otherStuff();& & }}?&Code similar to that gave me a 'class not found' error when using __autoload(). Using spl_autoload_register() with the exact same autoload function fixed the problem.
To find out whether a class can be autoloaded, you can use autoload in this way:&?phpfunction __autoload($className) {& & if (file_exists($className . '.php')) require $className . '.php';& & else throw new Exception('Class "' . $className . '" could not be autoloaded'); }function canClassBeAutloaded($className) {& & try {& & & & class_exists($className);& & & & return true;& & }& & catch (Exception $e) {& & & & return false;& & }}?&
Hi,Because the scripting engine just find the class declaration in the body of the __autoload() function, you also can declare the missing class in the __autoload() function. (No need to include or require a file.)Let's see the following code:Example 1.:&?phpfunction __autoload($className){& & echo "Now loading: $className&br /&";& & & & class SuperClass {& & }}class DerivedClass extends SuperClass {}class AnotherDerivedClass extends SuperClass {}?&The scripting engine will found the SuperClass class.Example 2.:You also can do it with the eval function, and if you dinamycally declare the class, you don't get a Fatal Error, and you can do many interesting things wi)&?phpfunction __autoload($className){& & echo "Now loading: $className&br /&";& & & & eval("class $className {}");}class DerivedClass extends SuperClass {}class AnotherDerivedClass extends SuperClass {}?&
Hi there,I have developed a small script, that can scan recursively folders and files ang generate array of associations between classes/interfaces and their locations. It accepts several incoming parameters and it's very simple to use. An example of generated array is shown bellow.&?php & & $autoload_list = array (& & & 'classes' =& array (& & & & 'A' =& array ('path' =& 'Project/Classes/Children/A.php',& & & & & 'extends' =& array (), 'implements' =& array ('I1')),& & & & 'C' =& array ('path' =& 'Project/Classes/C.php',& & & & & 'extends' =& array ('B'), 'implements' =& array ('I1', 'I3')),& & & ),& & & 'interfaces' =& array (& & & & 'I2' =& array ('path' =& 'Project/Interfaces/blablabla.php', 'extends' =& array ('I1')),& & & & 'I1' =& array ('path' =& 'Project/Interfaces/I1.php', 'extends' =& array ()),& & & ),& & );?&When you know names and their locations, you know everything to load these classes. It uses regular expressions to identify if class/interfaces is located in the current file.I tried to post the code, but it's very long. You can download the script from
About static classes that need initialisation before use (problem discussed by adam at greatbigmassive dot net and kalkamar at web dot de below).Simple problems have often simple solutions. Here is my approach:First, my __autoload function is very simple:&?phpfunction __autoload ($class_name){& & if (preg_match('|^\w+$|', $class_name))& & & & include "./packages/$class_name.php";}?&(The "if/preg_match" line is just a simple yet robust security check. Moreover I use "include" and not "require"/"require_once", so that if the file is not found, the __autoload function does nothing, and my script dies eventually with a meaningful "Class 'foo' not found"& fatal error.)Now, when I define a class "foo" which requires initialisation before use, I just write the initialisation code after the definition of the class in the file "packages/foo.php":&?phpclass foo{& & }?&That's it. No need for an &? init() ?& or a &? __construct() ?& method.
To use autoload function with namespaces you should remember to define it in main scope in "\" namespace.
Another way of throwing exceptions inside an __autoload() function:&?phpfunction myExceptionHandler($e) {& & }set_exception_handler('myExceptionHandler');function __autoload($class) {& & if (class_exists($class, false) || interface_exists($class, false)) {& & & && & & & }& & try {& & & & @require_once('path/to/' . $class . '.php');& & & & if (!class_exists($class, false) || !interface_exists($class, false)) {& & & & & & throw new Exception('Class ' . $class . ' not found');& & & & }& & }& & catch (Exception $e) {& & & & myExceptionHandler($e);& & }}?&
I've made this little script here which looks in a dir, and loads all the classed, and includes their files.$myDirectory = opendir("required/classes");// get each entrywhile($entryName = readdir($myDirectory)) {& & $dirArray[] = $entryN}// close directoryclosedir($myDirectory);//& & count elements in array$indexCount& & = count($dirArray);sort($dirArray);for($index=0; $index & $indexC $index++) {& & if($dirArray[$index] != '.' AND $dirArray[$index] != '..') {& & & & include("required/classes/$dirArray[$index]");& & & & $classname = strtolower($dirArray[$index]);& & & & $classname = str_replace('.php','',$classname);& & & & $classinit = str_replace('.php','',$dirArray[$index]);& & & & $$classname = new $& & }}
Note: if you're experiencing unexpected "failed opening required 'filename.php' (include..." errors:If you placed your autoload function in an external file which you're requiring at the head of every script, be cautious of some odd behavior regarding PHP's idea of the current working directory.I ran into some unexpected path issues when my include file was placed in a subdirectory directory. The solution to my problems was to make sure that the autoload script being included is in the same directory as the calling script.
Here is the most complete version of __autoload exception i guess.The best thing is that it can throw any exception plus the exception is fully functional.&?phpclass AutoloadException extends Exception { }class AutoloadExceptionRetranslator extends Exception{& & public function __construct($serializedException)& & {& & & & throw unserialize($serializedException);& & }}function __autoload($classname){& & if(!file_exists($classname))& & {& & & & $autoloadException = serialize(new AutoloadException("Class $classname could not be found"));& & & & return eval("& & & & & & class $classname& & & & & & {& & & & & & & & function __construct(\$a=0, \$b=0, \$c=0, \$d=0, \$e=0, \$f=0, \$g=0, \$h=0, \$i=0)& & & & & & & & {& & & & & & & & & & throw new AutoloadExceptionRetranslator('$autoloadException');& & & & & & & & }& & & & & & }& & & & ");& & }& & else& & {& & & & require_once $classname;& & }}try{& & $anyObject = new AnyNonExistantClass();}catch (AutoloadException $e){& & print_r($e-&getTrace());}?&
If you'd like '__autoload()' to support multiple class folders, each containing multiple class files (one per class), you may want to try something like this (file '__autoload.php'):&?phpdefine('CLASS_FILENAME_SUFFIX', '.class.php');function __autoload($className){& & $__autoloadAbsolutePath = dirname(__FILE__);& & $pathStart = $__autoloadAbsolutePath .& & & & DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR;& & $classPath = PATH_SEPARATOR . $pathStart .& & & & 'classlibs' . DIRECTORY_SEPARATOR . 'lib1';& & $oldIncludePath = get_include_path();& & set_include_path($oldIncludePath . $classPath);& & require_once($className . CLASS_FILENAME_SUFFIX);& & set_include_path($oldIncludePath);}?&As your web application develops, new paths containing class files can be added into the '$classPath' variable within '__autoload()'. If hard-coding the '$classPath' variable isn't to your taste, you could arrange for its value to come from 'outside' in whatever way you like.Any comments gratefully received.
An issue I've had with using the __autoload function is getting it into the application.You have to have the function included in every topmost script. This is a pain if the entire application is OOP and an "app" can be just a component of another "app".A solution I've found is to use php.ini's auto_prepend_file setting.Mine is set to ...auto_prepend_file = auto_loader.phpThe auto_loader.php script contains a single function. The __autoload() function.The include_dir path IS examined to find this file, so you can just put it with the rest of your includable files.A useful additional facility here is that you could log which classes are used by a script at runtime. Very useful if you have object factories and can't know the load at design time.Also, assigning the uncaught exception handler and the error handlers in this file means your entire site WILL have some global protection without you having to deal with it on a script by script basis.If you do not have access to the PHP.INI file, or you are running on a shared server, you may not be able to set this property. In those cases, you may be able to set the value using .htaccess. (NOTE: UNTESTED as I don't use Apache).&IfModule mod_php5.c&& php_value auto_prepend_file "auto_loader.php"&/IfModule&You COULD therefore have a different set of rules per subdomain (if you have multiple subdomains, say, live, test, beta, devel) or whatever takes your fancy.For more details on this see the "Description of core php.ini directives" ()
In reply to quetzalcoatl:Generally, I would advise for each class to have it's own file, and hold nothing besides that class. Just define __autoload() in a/the infrastructure file -- a/the file that does the behavioral logic, and there should be no need to redefine it in a class' file.
The autoload-feature allows to add the behavior of static constructors (like in C#). Static constructors should be called on the first occurence of a class reference - typically a 'new' operator or a static call to a class's operation.They can be used used to initialize complex static properties.And here is an easy and save way how it can be done:Content of MyClass.class.php5:&?phpclass MyClass{& & & & public static function _construct()& & {& & & & echo '&div&static constructor&/div&';& & }& & & & public function __construct()& & {& & & & echo '&div&dynamic constructor&/div&';& & }& & }?&Content of index.php5:&?phpfunction __autoload($aClassName){& & require_once ($aClassName . '.class.php5');& & $staticConstructorReference = array($aClassName, '_construct');& & & & if (is_callable($staticConstructorReference))& & {& & & & call_user_func($staticConstructorReference);& & }}$article = new MyObject();?&
This page states that autoloading does not work when PHP is used in CLI mode but a simple test seems to contradict this.Create a file /tmp/Foo.php containing:&?phpclass Foo {& & public function __construct() {& & & & echo "Inside the Foo constructor\n";& & }}?&Create a script (NOT in /tmp) containing:&?phpfunction test_autoload($class) {& & require_once '/tmp/'.$class.'.php';}spl_autoload_register('test_autoload');$foo = new Foo();?&Execute the script on the command line. The echo statement in the constructor produces output to STDOUT.This also works with __autoload&?phpfunction __autoload($class) {& & require_once '/tmp/'.$class.'.php';}$foo = new Foo();?&
Decided to warm up to autoload,but wanted it to use the include_path.Good default behavior.function __autoload($class_name) {& & & $include_path = get_include_path();& & & $include_path_tokens = explode(':', $include_path);& & & & & & foreach($include_path_tokens as $prefix){& & & && $path = $prefix . '/' . $class_name . '.php';& & & && if(file_exists($path)){& & & & & & require_once $& & & & & && & & & & }& & && }& & }
If you would like __autoload to throw an exception when the class cannot be loaded instead of causing a fatal error, consider this:&?phpfunction __autoload ($className){& & $fileName = str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';& & $status = (@include_once $fileName);& & & & & & if ($status === false) {& & & & eval(sprintf('class %s {func' . 'tion __construct(){throw new Project_Exception_AutoLoad("%s");}}', $className, $className));& & }&& }$pageController = 'Project_My_Class'; try {& $obj = new $pageController();} catch (Project_Exception_AutoLoad $e) {& & header('HTTP/1.0 404 Not Found');& & printf('&h1&Not Found&/h1&&p&The requested page %s was not found on this server.&/p&&hr /&&em&$id$&/em&', $_SERVER['REQUEST_URI']);}?&
As an addendum to #91119 I would suggest adding class_exists() into that solution. I've just implemented autoloading based on the code provided there and ran into a problem where a file had the same name as a class, existed in the directory structure prior to the file that had the actual class and as a result was being included first and resulting in a 'class not found' error.&?phpif(file_exists($path)) {& & require_once $path;& & if(class_exists($class_name)) {& & & && & }}?&
Another workaround for Exception problem (Klaus Schneider style)&?phpdefine('CLASS_DIR', 'php/classes/');function __autoload($name) {& & if($exists = !class_exists($name) && file_exists($class = CLASS_DIR.$name.'.class.php'))& & & & require $class;& & elseif(!$exists) {& & & & eval('class '.$name.' extends Exception {}');& & & & throw new $name('[__autoload] this file doesn\'t exists: '.$class);& & }}try {& & new Undefined;}catch(Undefined $e) {& & echo $e-&getMessage();}catch(Exception $e) {& & echo $e-&getMessage();}?&
To sandrejev at gmail dot com below: if you create the exception in the __autoload() and serialize it, then when you try to access the same missing class later (in another place in the code), then the exception will contain invalid stack trace.Also, here's an excellent blog post that discusses the consequences of using eval() as well as provides an example to handle static method calls and namespaces:
Be careful with using that eval() trick within __autoload().If you use reflection in your code, the so called trick, *can* provide ill side effects.For example -&$reflection = new reflectionClass('some_class');if (FALSE === $reflection-&isSubClassOf('another_class')){& & throw new Exception('Class "some_class" must extend base class "another_class"');}If the real class "another_class" doesnt exist at the time, or "some_class" doesn't extend "another_class", with the reflection test, the so called eval() trick, creates a dummy "another_class", thereby making the reflection test useless...
__autoload() seems to work when saving objects as session variables as well:classLoader.php&?phpfunction __autoload($className) {& require_once("$className.php");}?&testClass.php&?phpclass testClass {& function __construct($propValue) {& & $this-&prop1 = $propValue;& }& function showProp() {& & return $this-&prop1;& }}?&page1.php&?phprequire_once('classLoader.php');session_start();$_SESSION['testObj'] = new testClass('foo');echo '&a href="page2.php"&Go to page 2&/a&';?&page2.php&?phprequire_once('classLoader.php');session_start();echo $_SESSION['testObj']-&showProp(); ?&Works with multiple session objects as well.& Tested on a Win2k/IIS machine.
If you want to throw an exception if a class isn't defined yet, use class_exists ():&?phpif (!class_exists ($className, false)) {& & throw new Exception ("Class $className is not defined.");}?&The second parameter indicates whether or not the __autoload () function should be called before checking for the class's existence.

我要回帖

更多关于 yaf自动加载类 的文章

 

随机推荐