热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

php嵌套函数闭包嵌套函数+递归调用的Fatal错误分析

嵌套函数定义时先判断function_exists防止递归调用外部函数导致两次定义内部函数导致致命错误看一下PHP手册中是如何说的:





嵌套函数 定义时 先判断function_exists 防止 递归调用外部函数 导致两次定义内部 函数 导致致命错误





看一下PHP手册中是如何说的:






function foo()

{

  function bar()

  {

    echo "I don't exist until foo() is called.\n";

  }

}





/* 现在还不能调用bar()函数,因为它还不存在 */





foo();





/* 现在可以调用bar()函数了,因为foo()函数

   的执行使得bar()函数变为已定义的函数 */







?> 

?





PHP 中的所有函数和类都具有全局作用域,可以在内部定义外部调用,反之亦然。





?





我们不妨先看一下函数:





function outer( $msg ) { 

    function inner( $msg ) { 

        echo 'inner: '.$msg.' '; 

    } 

    echo 'outer: '.$msg.' '; 

    inner( $msg ); 




意这里 内部是创建了一个 有名字的函数 并放到全局函数表中,
如果是 inner 定义变成 function(){} 匿名函数定义 则会类似create_function 创建一个 \0lamab_function1 (后面1自动递增) 的函数到全局函数表


如果加上 $obj = function inner() {};或者 $obj=function () {}; 则 是使用该有名函数或者匿名函数 创建一个闭包对象 (use 变量变成这个闭包类的静态对象)

注意如果是 $obj=function ..则一定 要加分号结束
function f()
{
    $a = 1;
    $b = 3;
    $func =  function ($a)use($b) {
        echo json_encode($a).PHP_EOL;
        echo json_encode($b).PHP_EOL;
    };
    return $func;
}
$func = f();
$func(3);
以上示例输出3 3

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;

    }

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






推荐阅读
  • 本文详细探讨了JDBC(Java数据库连接)的内部机制,重点分析其作为服务提供者接口(SPI)框架的应用。通过类图和代码示例,展示了JDBC如何注册驱动程序、建立数据库连接以及执行SQL查询的过程。 ... [详细]
  • 在前两篇文章中,我们探讨了 ControllerDescriptor 和 ActionDescriptor 这两个描述对象,分别对应控制器和操作方法。本文将基于 MVC3 源码进一步分析 ParameterDescriptor,即用于描述 Action 方法参数的对象,并详细介绍其工作原理。 ... [详细]
  • 本文详细介绍了Java中org.neo4j.helpers.collection.Iterators.single()方法的功能、使用场景及代码示例,帮助开发者更好地理解和应用该方法。 ... [详细]
  • 深入解析Spring Cloud Ribbon负载均衡机制
    本文详细介绍了Spring Cloud中的Ribbon组件如何实现服务调用的负载均衡。通过分析其工作原理、源码结构及配置方式,帮助读者理解Ribbon在分布式系统中的重要作用。 ... [详细]
  • 本文详细介绍了如何构建一个高效的UI管理系统,集中处理UI页面的打开、关闭、层级管理和页面跳转等问题。通过UIManager统一管理外部切换逻辑,实现功能逻辑分散化和代码复用,支持多人协作开发。 ... [详细]
  • 本文详细介绍了 Apache Jena 库中的 Txn.executeWrite 方法,通过多个实际代码示例展示了其在不同场景下的应用,帮助开发者更好地理解和使用该方法。 ... [详细]
  • Scala 实现 UTF-8 编码属性文件读取与克隆
    本文介绍如何使用 Scala 以 UTF-8 编码方式读取属性文件,并实现属性文件的克隆功能。通过这种方式,可以确保配置文件在多线程环境下的一致性和高效性。 ... [详细]
  • ASP.NET MVC中Area机制的实现与优化
    本文探讨了在ASP.NET MVC框架中,如何通过Area机制有效地组织和管理大规模应用程序的不同功能模块。通过合理的文件夹结构和命名规则,开发人员可以更高效地管理和扩展项目。 ... [详细]
  • Explore a common issue encountered when implementing an OAuth 1.0a API, specifically the inability to encode null objects and how to resolve it. ... [详细]
  • 本文介绍如何使用Objective-C结合dispatch库进行并发编程,以提高素数计数任务的效率。通过对比纯C代码与引入并发机制后的代码,展示dispatch库的强大功能。 ... [详细]
  • 本文详细介绍了如何解决Uploadify插件在Internet Explorer(IE)9和10版本中遇到的点击失效及JQuery运行时错误问题。通过修改相关JavaScript代码,确保上传功能在不同浏览器环境中的一致性和稳定性。 ... [详细]
  • 本文详细介绍了如何在Linux系统上安装和配置Smokeping,以实现对网络链路质量的实时监控。通过详细的步骤和必要的依赖包安装,确保用户能够顺利完成部署并优化其网络性能监控。 ... [详细]
  • 深入理解Java泛型:JDK 5的新特性
    本文详细介绍了Java泛型的概念及其在JDK 5中的应用,通过具体代码示例解释了泛型的引入、作用和优势。同时,探讨了泛型类、泛型方法和泛型接口的实现,并深入讲解了通配符的使用。 ... [详细]
  • 优化局域网SSH连接延迟问题的解决方案
    本文介绍了解决局域网内SSH连接到服务器时出现长时间等待问题的方法。通过调整配置和优化网络设置,可以显著缩短SSH连接的时间。 ... [详细]
  • 本文介绍了一种从与src同级的config目录中读取属性文件内容的方法。通过使用Java的Properties类和InputStream,可以轻松加载并获取指定键对应的值。 ... [详细]
author-avatar
很呆很傻很天真2010_545
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有