`
bardo
  • 浏览: 378350 次
  • 性别: Icon_minigender_1
  • 来自: 上海
博客专栏
D1407912-ab64-3e76-ae37-b31aa4afa398
浅述PHP设计模式
浏览量:11807
9d6df9f7-91da-3787-a37c-0e826525dd5d
Zend Framewor...
浏览量:10116
85b628bd-a2ed-3de2-a4b1-0d34985ae8b6
PHP的IDE(集成开发环...
浏览量:9504
社区版块
存档分类
最新评论

戏说PHP的嵌套函数

    博客分类:
  • PHP
阅读更多

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;
    }

 可以看出,嵌套函数,是一种有条件全局函数,你可以控制,在什么情况下提供这样的全局函数给用户使用。但也需要注意,过多的全局函数则会产生“全局污染”,所以,不可多用。

分享到:
评论
2 楼 bardo 2011-01-11  
see1di 写道
可以介紹一下這種嵌套的function在什么狀況下使用嗎?
還有就是這樣用的好處以及不好的地方,再就是這樣用的效率問題等.
期待....

我已说得比较清楚了呀:如果你要一个全局函数,而这个函数中有一个判断:
if(class_exists('class_name'){
}
那你不如直接在 'class_name'这个类的构造函数中定义你的这个函数。这样上面的判断就省掉了。
1 楼 see1di 2011-01-10  
可以介紹一下這種嵌套的function在什么狀況下使用嗎?
還有就是這樣用的好處以及不好的地方,再就是這樣用的效率問題等.
期待....

相关推荐

    戏说面向对象程序设计

    第一章面试受挫——代码无错就是好? 第二章代码规范、重构 第三章复制 VS复用 第四章业务的封装 第五章体会简单工厂模式的美妙 第六章工厂不好用了?...第十三章设计模式不能戏说!设计模式怎就不能戏说?

    戏说面向对象编程oop

    在《戏说面向对象程序设计C#版.pdf》这本书中,作者可能会以轻松幽默的方式讲解这些概念,通过实际示例帮助读者理解和掌握面向对象编程的思想和技巧。无论是Java还是C#开发者,深入理解OOP都能提升编程能力和代码...

    大班音乐:戏说脸谱.ppt

    在IT行业中,虽然"大班音乐:戏说脸谱.ppt"这个标题和描述似乎与传统艺术形式相关,而非直接的技术主题,但是我们可以从中抽象出一个重要的知识点:跨学科教育和数字媒体在教学中的应用。这涉及到如何利用信息技术来...

    戏说指针 作者 李志勇 是word文档

    《戏说指针》这篇文档由李志勇撰写,旨在帮助读者理解和掌握C/C++中的指针概念。指针在编程中扮演着重要的角色,它允许我们直接操作内存地址,提高程序的灵活性和效率。以下是关于指针的详细解析: 一、如何分析...

    戏说C#面向对象。。

    C#中的构造函数可以有参数,也可以是无参的,默认构造函数。析构函数则在对象销毁前调用,通常用于释放非托管资源。C#的析构函数用~标记,但一般推荐使用Finalize方法和 Dispose模式来处理资源清理。 8. 属性与索引...

    幼儿园大班歌唱教案:戏说脸谱.doc

    幼儿园大班歌唱教案:戏说脸谱.doc

    戏说面向对象程序设计C#版

    它允许程序在运行时获取类型的信息并调用任意的构造函数和方法。这是一种强大的工具,但也可能带来安全性和性能上的问题。 #### 六、设计模式原则 **设计模式原则** - **单一职责原则**:一个类应该只负责一项...

    戏说指针认知,心测有效

    指针的本质、指针的三要素、类型与变量名

    戏说23种设计模式 基于GOF的设计模式

    原型模式通过复制现有的实例来创建新对象,而不是通过构造函数创建新对象。这种模式在创建大量相似对象时特别有效。例如,在游戏中复制角色对象时,如果每个角色都有复杂的属性设置,那么直接复制现有的角色对象会比...

    幼儿园教案2021-幼儿园大班歌唱教案:戏说脸谱.doc

    幼儿园教案2021-幼儿园大班歌唱教案:戏说脸谱.doc 本教案旨在通过京剧《戏说脸谱》的唱歌活动,培养幼儿对中国国粹的认识和喜爱,提高幼儿的音乐能力和艺术鉴赏力。通过活动,幼儿可以初步学习京剧《戏说脸谱》的...

    戏说国学.doc

    戏说国学.doc

    戏说绩效工资.doc

    戏说绩效工资.doc

    戏说面向对象 c#版

    《戏说面向对象 C#版》是一本独特的编程教材,旨在通过轻松的对话形式,让初学者能够理解并掌握面向对象编程的核心概念。面向对象编程(Object-Oriented Programming,简称OOP)是现代软件开发中广泛采用的一种编程...

    戏说TCP网络编程.doc

    戏说TCP网络编程.doc

    戏说地沟油学习教案.pptx

    戏说地沟油学习教案.pptx

    戏说垃圾(环保相声).pdf

    戏说垃圾(环保相声).pdf

    戏说OOP

    类是对象的蓝图,它定义了对象的属性(数据成员)和方法(函数成员)。对象是类的实例,每个对象都有自己的状态(属性值)和行为(方法的执行)。类和对象的关系就像工厂和产品,类是工厂的模具,对象则是生产出来的...

Global site tag (gtag.js) - Google Analytics