最近在学习workerman的时候比较频繁的接触到回调函数,使用中经常会因为worker的使用方式不同,会用这两种不同的方式去调用外部的worker变量,这里就整理一下PHP闭包获取外部变量和global关键字声明变量的区别。

闭包

闭包是一个常见的概念,我们通常可以将其与回调函数配合使用,可以使代码更加简洁易读。

闭包可以通过拷贝的方式让函数使用父作用域中的变量。如:

$global = 'hello';

$bbb = function()use($global){
echo $global."\n";
};
$bbb();
//输出 'hello'

global关键字声明变量

通过global声明变量同样可以使函数体调用到函数外部的变量,不过global与use不同,globle关键字会使创建一个与外部变量同名的引用,并且在函数内对变量作出修改同样会作用域外部变量。

$global = 'hello';
$fun = function(){
global $global;
$global =' world';
echo $global."\n";
};
$fun();
// 输出 'world'

这里只是创建一个同名引用而已,并不会改变原本外部变量$global的作用域,也就是说在另外一个函数中调用该依旧需要声明或者使用闭包

$global = 'hello';
$fun = function(){
global $global;
$global =' world';
echo 'a:'.$global."\n";
}; $ccc = function(){
echo 'b:'.$global;
};
$fun()
$ccc()
/*
输出
a: world Notice: Undefined variable: global in xxxxxxx on line xx
*/

再稍微改一下代码,这样更容易对比闭包和global关键字声明变量这两种访问外部变量方式的区别。

<?php
$global = 'hello';
$fun = function(){
global $global;
$global ='world';
echo 'a:'.$global."\n";
}; $bbb = function()use($global){
$global = 'china';
echo 'c:'.$global."\n";
}; $fun(); echo 'b:'.$global."\n";
$bbb();
echo 'd:'.$global;

这里b和d两个输出可以看出来,global改变了外部变量的值,而闭包方式并没有。

输出:

a: world
b: world
c:china
d: world

最后再贴一个官方文档中比较经典的使用匿名函数,闭包与回调函数配合的例子:

class Cart
{
const PRICE_BUTTER = 1.00;
const PRICE_MILK = 3.00;
const PRICE_EGGS = 6.95; protected $products = array(); public function add($product, $quantity)
{
$this->products[$product] = $quantity;
} public function getQuantity($product)
{
return isset($this->products[$product]) ? $this->products[$product] :
FALSE;
} public function getTotal($tax)
{
$total = 0.00; $callback =
function ($quantity, $product) use ($tax, &$total)
{
$pricePerItem = constant(__CLASS__ . "::PRICE_" .
strtoupper($product));
$total += ($pricePerItem * $quantity) * ($tax + 1.0);
};
array_walk($this->products, $callback);
return round($total, 2);
}
} $my_cart = new Cart; $my_cart->add('butter', 1);
$my_cart->add('milk', 3);
$my_cart->add('eggs', 6); print $my_cart->getTotal(0.05) . "\n";

PHP 闭包获取外部变量和global关键字声明变量的区别的更多相关文章

  1. 【python】为什么修改全局的dict变量不用global关键字

    转自:http://my.oschina.net/leejun2005/blog/145911?fromerr=qnPCgI19#OSC_h4_8 为什么修改字典d的值不用global关键字先声明呢? ...

  2. ES5-ES6-ES7_let关键字声明变量

    let命令的介绍 let是ECMAScript6中新增的关键字,用于声明变量.它的用法类似于var var a = 3 let b = 4 let变量的声明 let 命令的特点不允许在同一作用域下声明 ...

  3. C++ —— 类中static和const关键字声明变量的初始化方式总结

    在类中声明变量/常量时,经常会用到static.const关键字.对于该变/常量的初始化问题,网上有许多相关文章,但是大多不够完善,或者存在错误.经过实际验证,总结如下: (注明:测试编译平台为VS2 ...

  4. javascript的var声明变量和不用var声明变量在全局作用域的区别;

    在全局作用域下,使用var定义的变量不可以delete,没有var 定义的变量可以delete.也就说明隐含全局变量严格来说不是真正的变量,而是全局对象的属性,因为属性可以通过delete删除,而变量 ...

  5. Java如何声明变量?JS如何声明变量?

    Java采用强类型变量检查,像C语言一样.所有变量在编译之前必须声明,而且不能使用没有赋值的变量.例如:int x;x=1234;char y='F';其中X=1234说明是一个整数,Y='F'说明是 ...

  6. 全局变量和局部变量(global关键字)

    1.定义在函数外部的就是全局变量,它的作用域从定义处一直到文件结尾. 2.函数内定义的变量就是局部变量,它的作用域为函数定义范围内. 3.函数之间存在作用域互不影响. 4.函数内访问全局变量需要 gl ...

  7. Java(2)详解注释&关键字&常量&变量&标识符

    作者:季沐测试笔记 原文地址:https://www.cnblogs.com/testero/p/15201497.html 博客主页:https://www.cnblogs.com/testero ...

  8. js声明变量的三种方式及作用域

      js声明变量的三种方式及作用域 CreateTime--2017年9月11日17:19:11 Author:Marydon 一.参考链接 本篇文章的创作灵感来源于博主-奔跑的铃铛关于js中cons ...

  9. js声明变量的三种方式

    JS 声明变量的三种方式 (1)使用变量步骤:a.声明-->b.赋值-->3.调用 正确用法: <script type="text/javascript"> ...

随机推荐

  1. SpringMVC: web.xml中声明DispatcherServlet时一定要添加load-on-startup标签

    游历SpringMVC源码后发现,在web.xml中注册的ContextLoaderListener监听器只是初始化了一个根上下文,仅仅完成了组件扫描和与容器初始化相关的一些工作,并没有探测到具体每个 ...

  2. 常用类(Date,Calendar,Math,枚举)

    1.日期时间类 计算机时间戳是指距离历元(1970-01-01 00:00:00:000)的时间间隔(以毫秒ms为单位). 如:计算机时间2019-04-29 14:14:00是该时间距离历元经过的毫 ...

  3. Python3 环境搭建

    Window 平台安装 Python: 以下为在 Window 平台上安装 Python 的简单步骤. 打开 WEB 浏览器访问 https://www.python.org/downloads/wi ...

  4. c# 根据当前时间获取,本周,本月,本季度,月初,月末,各个时间段

    DateTime dt = DateTime.Now;  //当前时间   DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") //24小时制 ...

  5. sysbench数据库压力测试

    sysbench是一款压力测试工具,可以测试系统的硬件性能,也可以用来对数据库进行基准测试 wget https://github.com/akopytov/sysbench/archive/1.0. ...

  6. oracle 查询非自增长分区的最大分区

    select a.table_owner, a.table_name, a.max_partition  from (select table_owner, table_name, max(parti ...

  7. 按行读取.txt文件,并按行写入到新文件中

    package com.test.io; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.Fi ...

  8. spring MVC 使用 hibernate validator验证框架,国际化配置

    spring mvc使用hibernate validator框架可以实现的功能: 1. 注解java bean声明校验规则. 2. 添加message错误信息源实现国际化配置. 3. 结合sprin ...

  9. strlen的容易tle情况

    for(int i=1;i<=strlen(**);i++ 这很容易tle 因为 strlen很大 int m=strlen(**)

  10. 基于SaaS的企业数据隐私保护平台

    导读 WireWheel成立于2016年,总部位于华盛顿,该公司致力于降低数据隐私保护合规能力建设的难度,帮助企业来应对复杂.严厉的法案.条例规定.2018年10月,公司获得了PSP Growth领投 ...