PHP闭包 - 获取闭包作用域原始类名

4

问题

我正在玩一个Laravel项目,想看看是否可以使用闭包来实现我的排序接口,我注意到当我使用dd()打印我的闭包时,它还会显示创建该闭包的类作为属性。

简化后的代码

// in my Order model class, i have a function that will return a closure
public static function defaultSortFunction(){
    $sortColumn = property_exists(self::class,'defaultSortingColumn') ? self::$defaultSortingColumn : 'created_at';

    return function($p,$n)use($sortColumn){
        return $p->$sortColumn <=> $n->$sortColumn;
    };
}

// in one of my controller I use for testing, I added these 2 methods for testing
public function index(){
    $sortFunction = Order::defaultSortFunction();
    $this->someOtherFunction($sortFunction);
    return 'done';
}

private function someOtherFunction($fn){
    dd($fn);

    // $scopeModel = get_class($fn); => Closure
    
    // example of how I can use this value later
    // $scopeModel::take(10)->get()->sort($fn);
}
someOtherFunction()dd() 的结果为:
^ Closure($p, $n) {#1308 ▼
  class: "App\Order"
  use: {
    $sortColumn: "created_at"
  }
}

问题

dd()的结果可以看出,闭包具有一个属性,表明它是在类App\Order中定义的。是否有任何方法可以访问这个值?

我已经尝试过get_class($fn),但正如预期的那样,它会返回"Closure",如果我尝试$fn->class,则会出现错误信息Closure object cannot have properties

2个回答

6

你可以使用 Reflection API 处理闭包,这比 debug_backtrace 更加简洁。

// in one of my controller I use for testing, I added these 2 methods for testing
public function index(){
    $sortFunction = Order::defaultSortFunction();
    $this->someOtherFunction($sortFunction);
    return 'done';
}

private function someOtherFunction($fn){
    $reflectionClosure = new \ReflectionFunction($fn);
    dd($reflectionClosure->getClosureScopeClass()->getName());
}

getClosureScopeClass 返回一个基于需要查找的类的 ReflectionClass 实例,而getName 则完成了这项工作。


3
好的回答。$reflectionClosure->getClosureThis() 也可以用来获取闭包绑定的实例(内部 $this)。 - mvorisek

0

当然,您可以通过在defaultSortFunction中的参数中注入类名来实现,但这显然不太好。

您应该能够使用以下方法从调用堆栈中提取调用类: https://www.php.net/manual/en/function.debug-backtrace.php

如果您使用limit参数,您应该能够将其限制为仅返回调用类而不再返回更多信息。

我不确定,但我怀疑它的性能并不特别好。


我知道我可以通过参数简单地传递类名,但我正在尝试弄清楚是否可以访问闭包的class属性以避免使用2个参数。您建议的调试回溯很有趣,但如果我理解正确的话,我必须在我的闭包内部调用它而不是外部。 - Helioarch
是的,你必须从闭包内部调用它,但它应该提供你所需的内容。 - Howard Tomlinson
通过使用不同的文本进行搜索,可以找到这个线程,其中提供了一些很好的建议,可以压缩它并使其更加优化:https://dev59.com/OHI95IYBdhLWcg3w3yJU - Howard Tomlinson
谢谢您的建议,但我仍然想知道如何访问该属性本身,这样我可以在其他情况下更灵活地使用它。 - Helioarch
那么你就没那么幸运了;虽然调用类名和函数是可用的,但该类的实际实例不可用。如果您需要在闭包内使用该属性的值,则必须通过参数传递它,或者在闭包内实例化一个临时副本并进行查询。 - Howard Tomlinson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接