热门标签 | 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;

    }

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






推荐阅读
  • 本文探讨了如何在Classic ASP中实现与PHP的hash_hmac('SHA256', $message, pack('H*', $secret))函数等效的哈希生成方法。通过分析不同实现方式及其产生的差异,提供了一种使用Microsoft .NET Framework的解决方案。 ... [详细]
  • 使用JS、HTML5和C3创建自定义弹出窗口
    本文介绍如何结合JavaScript、HTML5和C3.js来实现一个功能丰富的自定义弹出窗口。通过具体的代码示例,详细讲解了实现过程中的关键步骤和技术要点。 ... [详细]
  • 前文|功能型_品读鸿蒙HDF架构
    前文|功能型_品读鸿蒙HDF架构 ... [详细]
  • PHP 实现多级树形结构:构建无限层级分类系统
    在众多管理系统中,如菜单、分类和部门等模块,通常需要处理层级结构。为了高效管理和展示这些层级数据,本文将介绍如何使用 PHP 实现多级树形结构,并提供代码示例以帮助开发者轻松实现无限分级。 ... [详细]
  • This article explains how to check if a given string consists solely of English characters, including letters and numbers. It provides a practical PHP function for this purpose. ... [详细]
  • Python包管理工具pip的使用指南
    本文详细介绍了如何使用pip进行Python包的安装、管理和常见问题的解决方法,特别针对国内用户提供了优化建议。 ... [详细]
  • 本文介绍了如何在PHP Magento模型中自定义主键,避免使用默认的自动递增主键,并提供了解决方案和代码示例。 ... [详细]
  • 本文将详细探讨 Java 中提供的不可变集合(如 `Collections.unmodifiableXXX`)和同步集合(如 `Collections.synchronizedXXX`)的实现原理及使用方法,帮助开发者更好地理解和应用这些工具。 ... [详细]
  • HTTPS与TLS/SSL协议详解:握手及记录协议
    HTTPS,即HTTP over TLS/SSL,通过在HTTP通信层引入安全协议,确保数据传输的安全性。本文将深入探讨TLS/SSL协议的基本概念、HTTPS的必要性,以及TLS握手和记录协议的工作原理。 ... [详细]
  • Spring Cloud Config 使用 Vault 作为配置存储
    本文探讨了如何在Spring Cloud Config中集成HashiCorp Vault作为配置存储解决方案,基于Spring Cloud Hoxton.RELEASE及Spring Boot 2.2.1.RELEASE版本。文章还提供了详细的配置示例和实践建议。 ... [详细]
  • Redis安全防护深入解析
    本文详细探讨了如何通过指令安全、端口管理和SSL代理等措施有效保护Redis服务的安全性。 ... [详细]
  • 本文档详细介绍了在 Kubernetes 集群中部署 ETCD 数据库的过程,包括实验环境的准备、ETCD 证书的生成及配置、以及集群的启动与健康检查等关键步骤。 ... [详细]
  • Android中解析XML文件的实践指南
    本文详细介绍了在Android应用开发中解析XML文件的方法,包括从本地文件和网络资源获取XML文件的不同途径,以及使用DOM、SAX和PULL三种解析方式的具体实现。 ... [详细]
  • 在DELL Inspiron 14R上部署CentOS X64 6.4的详细步骤
    本文详细记录了在DELL Inspiron 14R笔记本电脑上安装CentOS X64 6.4操作系统的过程,包括遇到的问题及解决方法。 ... [详细]
  • Node.js 中 GET 和 POST 请求的数据处理
    本文详细介绍了如何在 Node.js 中使用 GET 和 POST 方法来处理客户端发送的数据。通过示例代码展示了如何解析 URL 参数和表单数据,并提供了完整的实现步骤。 ... [详细]
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社区 版权所有