在 laravel 的闭包(如 `reduce`、`array_reduce`)中直接使用 `$this` 会报错“using $this when not in object context”,因其脱离了对象作用域;应改用 `parent::methodname()` 或将闭包转为 `use ($this)` 形式(php 7.4+),但后者不推荐。
该错误的根本原因在于:PHP 匿名函数默认不继承外部作用域中的 $this。即使你在 OrdersGraphs 实例方法中定义了闭包,该闭包本身是一个独立的函数对象,并不具备对当前对象实例的隐式引用。因此,$this->stringToFloat(...) 在闭包内部是非法的——PHP 此时根本不知道 $this 指向谁。
✅ 正确做法:使用 parent::stringToFloat()
由于 stringToFloat() 是定义在父类 Graph 中的 public 实例方法,且当前上下文是 OrdersGraphs 的实例方法(即 $this 确实存在),你只需在闭包外调用该方法,再将结果传入即可。但更简洁、语义更清晰的方式是——在闭包中显式通过 parent:: 调用父类方法(前提是方法非 static,且当前类继承自该父类):
$totalInData = $data->reduce(function ($carry, $item) {
return $carry + parent::stringToFloat($item->cogs); // ✅ 合法:parent:: 在继承链中解析为 Graph::stringToFloat
}, 0); // ⚠️ 别忘了提供初始值(如 0),否则 reduce 可能返回 null 导致类型错误⚠️ 注意事项:
? 替代方案(不推荐,仅作技术说明):
PHP 7.4+ 支持在闭包中 use ($this),但强烈不建议:
$totalInData = $data->reduce(function ($carry, $item) use ($this) {
return $carry + $this->stringToFloat($item->cogs); // ❌ 危险!可能引发循环引用、内存泄漏,且违背封装原则
}, 0);此写法虽语法合法,但会使闭包持有对外部对象的强引用,干扰垃圾回收,且模糊了方法职责边界。
✅ 最佳实践总结:
这样,你的 OrdersGraphs 不仅能复用 Graph 的通用能力,还能保持面向对象设计的清晰性与健壮性。