PHP很早就支持嵌套函数了。并是不PHP5.3有闭包时才有的。然而,它却不是象JS,AS那样的闭包嵌套。即它的嵌套函数根本无闭包模式的逃脱。
PHP嵌套函数有一些特别之处。最特别的是,当外部函数被调用时,内部函数就会自动进入全局域中,成为新的定义函数。
所以,当外部函数确保是被调用一次,不会被调用二次,那么,可以写嵌套函数在其中。否则,就会引发致命错误。
但若我们仍想在一个可被调用多次的函数中定义一个内部函数,那么,该如何处理?
我们象在全局定义函数一样使用:
if (!function_exists('你的函数名')){
}
因此,全局函数的使用,常常用于一些特别的目的。同时要清楚,这样的函数,实际就是定义的全局函数。因此,它没有类对它封装,更没有命名空间。
看一下PHP手册中是如何说的:
<?php
function foo()
{
function bar()
{
echo "I don't exist until foo() is called.\n";
}
}
/* 现在还不能调用bar()函数,因为它还不存在 */
foo();
/* 现在可以调用bar()函数了,因为foo()函数
的执行使得bar()函数变为已定义的函数 */
bar();
?>
PHP 中的所有函数和类都具有全局作用域,可以在内部定义外部调用,反之亦然。
我们不妨先看一下函数:
function outer( $msg ) {
function inner( $msg ) {
echo 'inner: '.$msg.' ';
}
echo 'outer: '.$msg.' ';
inner( $msg );
}
inner( 'test1' ); // Fatal error: Call to undefined function inner()
//上面出错,是因为外部函数还没有调用,所以出错。
outer( 'test2' ); // outer: test2 inner: test2
inner( 'test3' ); // inner: test3
outer( 'test4' ); // Fatal error: Cannot redeclare inner()
//上面出错,是因为,外部函数被调用时,内部函数被重定义了。
这里,我们再看一下,一个自动加载类,其中的做法
static public function initAutoload(){
//初始化Autoload Callable List
self::setAutoloadCallableList();
//初始化 $classList
self::$classList = uxAutoloadConfig::getClassList();
//如果有spl_autoload_register,则直接设置
if (function_exists('spl_autoload_register')){
ini_set('unserialize_callback_func', 'spl_autoload_call');
spl_autoload_register(array('uxAutoload', 'splSimpleAutoload'));
}elseif (!function_exists('__autoload')){ //否则要使用__autoload函数。
ini_set('unserialize_callback_func', '__autoload');
//因为没有spl_autoload, 所以, 这里要定义一个__autoload函数.
function __autoload($class){
if( self::splSimpleAutoload($class)== true)
return true;
//因为没有spl_autoload_register,所以在类未加载成功时,要处理Callable List
foreach(self::$autoloadCallables as $key => $callable ){
if (class_exists($class, false)){
$classObj=self::$autoloadObjectList[$callable[0]];
}else{
$className=$callable[0];
$classObj = new $className();
self::$autoloadObjectList[$class] = &$classObj;
}
if (method_exists($classObj,$callable[1])){
$method=$callable[1];
if ($classObj->$method($class)==true)
return true;
}else{
trigger_error('Autoload method '.$method.' not found in class '.$className.'!', E_USER_ERROR);
return false;
}
}
}
}
}
很明显,它是定义了一个内部函数function __autoload($class),以防没有'spl_autoload_register'。而这个类的这个函数,任一request请求中,只运行一次。
但是,如果要运行多次,比如,以下函数中,定义了一个全局的TRACE函数。这个函数的目的是在用户使用标准MVC方式时,才提供此TRACE函数给用户使用。引导用户走正确的方向。实际上,也可以看出,如果用户用不到此类,很可能,TRACE函数就不是这么几行代码。由此,这一做法确实精简了相当多的代码。
static public function getInstance($config = 0 ,$className=NULL){
if (!function_exists('trace')){ //specially for ajax debug!!
function trace($var){
$string=print_r($var,true);
require_once(UXERHDIR.'../uxLogger/uxLogger.class.php');
uxLogger::getInstance()->logg('INFO',
'/*************************** BEGIN INFO BY TRACE: ***************************\r\n '
.$string
.'/*************************** END INFO BY TRACE ***************************\r\n' );
}
}
if (!isset(self::$instance)){
if (is_array($config)){
$options=$config;
}else{
if ($config == NULL)
$config = 0;
$options=uxErrorHandlerConfig::get($config);
}
$class=($className==NULL)?'uxErrorHandler':$className;
self::$instance = new $class($options);
}
return self::$instance;
}
可以看出,嵌套函数,是一种有条件全局函数,你可以控制,在什么情况下提供这样的全局函数给用户使用。但也需要注意,过多的全局函数则会产生“全局污染”,所以,不可多用。
分享到:
相关推荐
第一章面试受挫——代码无错就是好? 第二章代码规范、重构 第三章复制 VS复用 第四章业务的封装 第五章体会简单工厂模式的美妙 第六章工厂不好用了?...第十三章设计模式不能戏说!设计模式怎就不能戏说?
在《戏说面向对象程序设计C#版.pdf》这本书中,作者可能会以轻松幽默的方式讲解这些概念,通过实际示例帮助读者理解和掌握面向对象编程的思想和技巧。无论是Java还是C#开发者,深入理解OOP都能提升编程能力和代码...
在IT行业中,虽然"大班音乐:戏说脸谱.ppt"这个标题和描述似乎与传统艺术形式相关,而非直接的技术主题,但是我们可以从中抽象出一个重要的知识点:跨学科教育和数字媒体在教学中的应用。这涉及到如何利用信息技术来...
《戏说指针》这篇文档由李志勇撰写,旨在帮助读者理解和掌握C/C++中的指针概念。指针在编程中扮演着重要的角色,它允许我们直接操作内存地址,提高程序的灵活性和效率。以下是关于指针的详细解析: 一、如何分析...
C#中的构造函数可以有参数,也可以是无参的,默认构造函数。析构函数则在对象销毁前调用,通常用于释放非托管资源。C#的析构函数用~标记,但一般推荐使用Finalize方法和 Dispose模式来处理资源清理。 8. 属性与索引...
幼儿园大班歌唱教案:戏说脸谱.doc
它允许程序在运行时获取类型的信息并调用任意的构造函数和方法。这是一种强大的工具,但也可能带来安全性和性能上的问题。 #### 六、设计模式原则 **设计模式原则** - **单一职责原则**:一个类应该只负责一项...
指针的本质、指针的三要素、类型与变量名
原型模式通过复制现有的实例来创建新对象,而不是通过构造函数创建新对象。这种模式在创建大量相似对象时特别有效。例如,在游戏中复制角色对象时,如果每个角色都有复杂的属性设置,那么直接复制现有的角色对象会比...
幼儿园教案2021-幼儿园大班歌唱教案:戏说脸谱.doc 本教案旨在通过京剧《戏说脸谱》的唱歌活动,培养幼儿对中国国粹的认识和喜爱,提高幼儿的音乐能力和艺术鉴赏力。通过活动,幼儿可以初步学习京剧《戏说脸谱》的...
戏说国学.doc
戏说绩效工资.doc
《戏说面向对象 C#版》是一本独特的编程教材,旨在通过轻松的对话形式,让初学者能够理解并掌握面向对象编程的核心概念。面向对象编程(Object-Oriented Programming,简称OOP)是现代软件开发中广泛采用的一种编程...
戏说TCP网络编程.doc
戏说地沟油学习教案.pptx
戏说垃圾(环保相声).pdf
类是对象的蓝图,它定义了对象的属性(数据成员)和方法(函数成员)。对象是类的实例,每个对象都有自己的状态(属性值)和行为(方法的执行)。类和对象的关系就像工厂和产品,类是工厂的模具,对象则是生产出来的...