Skip to content

Commit

Permalink
Bind closures when using macros to allow access to $this and static.
Browse files Browse the repository at this point in the history
  • Loading branch information
taylorotwell committed Dec 27, 2014
1 parent e41a29c commit 9849c3c
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 3 deletions.
24 changes: 22 additions & 2 deletions src/Illuminate/Support/Traits/MacroableTrait.php
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<?php namespace Illuminate\Support\Traits;

use Closure;
use BadMethodCallException;

trait MacroableTrait {
Expand Down Expand Up @@ -47,7 +48,14 @@ public static function __callStatic($method, $parameters)
{
if (static::hasMacro($method))
{
return call_user_func_array(static::$macros[$method], $parameters);
if (static::$macros[$method] instanceof Closure)
{
return call_user_func_array(Closure::bind(static::$macros[$method], null, get_called_class()), $parameters);
}
else
{
return call_user_func_array(static::$macros[$method], $parameters);
}
}

throw new BadMethodCallException("Method {$method} does not exist.");
Expand All @@ -64,7 +72,19 @@ public static function __callStatic($method, $parameters)
*/
public function __call($method, $parameters)
{
return static::__callStatic($method, $parameters);
if (static::hasMacro($method))
{
if (static::$macros[$method] instanceof Closure)
{
return call_user_func_array(static::$macros[$method]->bindTo($this, get_class($this)), $parameters);
}
else
{
return call_user_func_array(static::$macros[$method], $parameters);
}
}

throw new BadMethodCallException("Method {$method} does not exist.");
}

}
24 changes: 23 additions & 1 deletion tests/Support/SupportMacroTraitTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ public function setUp()
private function createObjectForTrait()
{
$traitName = 'Illuminate\Support\Traits\MacroableTrait';

return $this->getObjectForTrait($traitName);
}

Expand All @@ -33,4 +32,27 @@ public function testRegisterMacroAndCallWithoutStatic()
$this->assertEquals('Taylor', $macroTrait->{__CLASS__}());
}


public function testWhenCallingMacroClosureIsBoundToObject()
{
TestMacroTrait::macro('tryInstance', function() { return $this->protectedVariable; } );
TestMacroTrait::macro('tryStatic', function() { return static::getProtectedStatic(); } );
$instance = new TestMacroTrait;

$result = $instance->tryInstance();
$this->assertEquals('instance', $result);

$result = TestMacroTrait::tryStatic();
$this->assertEquals('static', $result);
}

}

class TestMacroTrait {
use Illuminate\Support\Traits\MacroableTrait;
protected $protectedVariable = 'instance';
protected static function getProtectedStatic()
{
return 'static';
}
}

2 comments on commit 9849c3c

@yateric
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems HHVM still not support Closure::bindTo, so that the app using macro in HHVM will be broken.

facebook/hhvm#1203

@GrahamCampbell
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@yateric Not true. This will be fixed in hhvm 3.5.0.

Please sign in to comment.