是否可以在不使用全局变量的情况下在 PHP 5.2.x 中模拟闭包?我可以想出一种方法,将所需变量作为额外参数传递给闭包,但这并不是最佳实践。
有什么想法吗?
最佳答案
有趣的问题。我会说根本不可能,但让我们看看
引用 IBM - What's new in PHP5.3, Part 2
A closure is a function that is evaluated in its own environment, which has one or more bound variables that can be accessed when the function is called.
进一步(强调我的)
Variables to be imported from the outside environment are specified in the use clause of the closure function definition. By default, they are passed by value, meaning that if we would update the value passed within the closure function definition, it would not update the outside value.
使用 global 将通过引用传递,尽管可以通过在 use 子句中使用 & 将变量通过引用与闭包绑定(bind), 它已经偏离了 5.3 的默认行为。
$var = 'yes';
$fn = create_function('', 'global $var; $var = "no";');
$fn();
echo $var; // outputs no
您可以复制全局变量以便按值使用它,例如
$var = 'yes';
$fn = create_function('', 'global $var; $tmp = $var; $tmp = "no";');
$fn();
echo $var; // outputs yes
此外,全局变量的值(使用create_function时)不会在创建函数时计算(绑定(bind)),而是在函数运行时计算(绑定(bind))
$var = 'yes';
$fn = create_function('', 'global $var; $tmp = $var; return $tmp;');
$var = 'maybe';
echo $fn(); // outputs maybe
$var = 'yes';
$fn = function() use ($var) { return $var; };
$var = 'maybe';
echo $fn(); // outputs yes
同样重要的是
When defined within an object, one handy thing is that the closure has full access to the object through the $this variable, without the need to import it explicitly. *Though I think this was dropped in final PHP5.3
这对于 global 关键字是不可能的,您也不能只使用 $this。使用 create_function 定义函数体时,无法从类中引用属性。
class A {
protected $prop = 'it works';
public function test()
{
$fn = create_function('', 'echo $this->prop;');
return $fn;
}
}
$a = new A;
$fn = $a->test();
$fn();
会导致
Fatal error: Using $this when not in object context
总结一下
虽然您可以创建一个从全局范围导入变量的函数,但您不能使用来自另一个范围的变量来创建一个函数。因为从技术上讲,您在使用 create_function 时没有绑定(bind),而是在执行创建的函数时导入,所以我想争辩说这种限制使闭包成为 lambda。
编辑:下面由 Onno Marsman 提供的解决方案非常不错。它没有完全模拟闭包,但实现非常接近。
关于php - 是否可以在不使用全局变量的情况下模拟 PHP 5.2.x 中的闭包?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2209327/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru
使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta
查看Ruby的CSV库的文档,我非常确定这是可能且简单的。我只需要使用Ruby删除CSV文件的前三列,但我没有成功运行它。 最佳答案 csv_table=CSV.read(file_path_in,:headers=>true)csv_table.delete("header_name")csv_table.to_csv#=>ThenewCSVinstringformat检查CSV::Table文档:http://ruby-doc.org/stdlib-1.9.2/libdoc/csv/rdoc/CSV/Table.html
这是在Ruby中设置默认值的常用方法:classQuietByDefaultdefinitialize(opts={})@verbose=opts[:verbose]endend这是一个容易落入的陷阱:classVerboseNoMatterWhatdefinitialize(opts={})@verbose=opts[:verbose]||trueendend正确的做法是:classVerboseByDefaultdefinitialize(opts={})@verbose=opts.include?(:verbose)?opts[:verbose]:trueendend编写Verb
是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou
这个问题在这里已经有了答案:Checktoseeifanarrayisalreadysorted?(8个答案)关闭9年前。我只是想知道是否有办法检查数组是否在增加?这是我的解决方案,但我正在寻找更漂亮的方法:n=-1@arr.flatten.each{|e|returnfalseife
我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re
我发现ActiveRecord::Base.transaction在复杂方法中非常有效。我想知道是否可以在如下事务中从AWSS3上传/删除文件:S3Object.transactiondo#writeintofiles#raiseanexceptionend引发异常后,每个操作都应在S3上回滚。S3Object这可能吗?? 最佳答案 虽然S3API具有批量删除功能,但它不支持事务,因为每个删除操作都可以独立于其他操作成功/失败。该API不提供任何批量上传功能(通过PUT或POST),因此每个上传操作都是通过一个独立的API调用完成的
我有一个包含多个键的散列和一个字符串,该字符串不包含散列中的任何键或包含一个键。h={"k1"=>"v1","k2"=>"v2","k3"=>"v3"}s="thisisanexamplestringthatmightoccurwithakeysomewhereinthestringk1(withspecialcharacterslike(^&*$#@!^&&*))"检查s是否包含h中的任何键的最佳方法是什么,如果包含,则返回它包含的键的值?例如,对于上面的h和s的例子,输出应该是v1。编辑:只有字符串是用户定义的。哈希将始终相同。 最佳答案