1
0
mirror of https://github.com/flarum/core.git synced 2025-06-06 06:35:09 +02:00

Pass callback wrapper parameters by reference (#2485)

Because invokable class objects are not directly called and instead it's the callback wrapper that calls these objects, it's currently not possible to receive arguments by reference on an invokable class.

To fix this we pass the arguments by reference by default when calling the object in the callback wrapper.
This commit is contained in:
Sami Mazouz 2020-12-06 20:58:45 +01:00 committed by GitHub
parent cfa533ebd6
commit 056d420c7b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 142 additions and 2 deletions

View File

@ -24,10 +24,10 @@ class ContainerUtil
public static function wrapCallback($callback, Container $container)
{
if (is_string($callback)) {
$callback = function () use ($container, $callback) {
$callback = function (&...$args) use ($container, $callback) {
$callback = $container->make($callback);
return call_user_func_array($callback, func_get_args());
return $callback(...$args);
};
}

View File

@ -0,0 +1,140 @@
<?php
/*
* This file is part of Flarum.
*
* For detailed copyright and license information, please view the
* LICENSE file that was distributed with this source code.
*/
namespace Flarum\Tests\unit\Foundation;
use Flarum\Foundation\ContainerUtil;
use Flarum\Tests\unit\TestCase;
use Illuminate\Container\Container;
class ContainerUtilTest extends TestCase
{
private $container;
protected function setUp()
{
parent::setUp();
$this->container = new Container();
}
/** @test */
public function it_works_with_closures()
{
$callback = ContainerUtil::wrapCallback(function ($array) {
$array['key'] = 'newValue';
return 'return';
}, $this->container);
$array = ['key' => 'value'];
$return = $callback($array);
$this->assertEquals('value', $array['key']);
$this->assertEquals('return', $return);
}
/** @test */
public function it_works_with_invokable_classes()
{
$callback = ContainerUtil::wrapCallback(CustomInvokableClass::class, $this->container);
$array = ['key' => 'value2'];
$return = $callback($array);
$this->assertEquals('value2', $array['key']);
$this->assertEquals('return2', $return);
}
/** @test */
public function it_works_with_invokable_objects()
{
$callback = ContainerUtil::wrapCallback(new class {
public function __invoke($array)
{
$array['key'] = 'newValue5';
return 'return5';
}
}, $this->container);
$array = ['key' => 'value5'];
$return = $callback($array);
$this->assertEquals('value5', $array['key']);
$this->assertEquals('return5', $return);
}
/** @test */
public function it_allows_passing_args_by_reference_on_closures()
{
$callback = ContainerUtil::wrapCallback(function (&$array) {
$array['key'] = 'newValue3';
return 'return3';
}, $this->container);
$array = ['key' => 'value3'];
$return = $callback($array);
$this->assertEquals('newValue3', $array['key']);
$this->assertEquals('return3', $return);
}
/** @test */
public function it_allows_passing_args_by_reference_on_invokable_classes()
{
$callback = ContainerUtil::wrapCallback(SecondCustomInvokableClass::class, $this->container);
$array = ['key' => 'value4'];
$return = $callback($array);
$this->assertEquals('newValue4', $array['key']);
$this->assertEquals('return4', $return);
}
/** @test */
public function it_allows_passing_args_by_reference_on_invokable_objects()
{
$callback = ContainerUtil::wrapCallback(new class {
public function __invoke(&$array)
{
$array['key'] = 'newValue6';
return 'return6';
}
}, $this->container);
$array = ['key' => 'value6'];
$return = $callback($array);
$this->assertEquals('newValue6', $array['key']);
$this->assertEquals('return6', $return);
}
}
class CustomInvokableClass
{
public function __invoke($array)
{
$array['key'] = 'newValue2';
return 'return2';
}
}
class SecondCustomInvokableClass
{
public function __invoke(&$array)
{
$array['key'] = 'newValue4';
return 'return4';
}
}