Created
February 29, 2012 17:10
-
-
Save funkatron/1942528 to your computer and use it in GitHub Desktop.
Half-done features in PHP, pt 1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
$app->foo = function() { echo 'test'; die;}; | |
$app->foo(); // ERROR | |
$f = $app->foo; | |
$f(); // SUCCESS | |
/********************************************************* | |
Here's a modification to __call that would let you call | |
dynamically assigned methods in the normal fashion. This | |
is of limited uselfulness in PHP 5.3 because you can't | |
reference $this | |
**********************************************************/ | |
<?php | |
class Foo | |
{ | |
public function baz($txt) { | |
echo "BAZ: $txt\n"; | |
} | |
public function __call($name, $arguments) { | |
if (isset($this->{$name}) && $this->{$name} instanceof Closure) { | |
$m = $this->{$name}; | |
return call_user_func_array($m, $arguments); | |
} | |
} | |
} | |
$foo = new Foo(); | |
$foo->bar = function($txt) { echo "BAR: $txt\n"; }; | |
$foo->bar('This method was dynamically added'); | |
$foo->baz('This method was defined in the class'); | |
/********************************************************* | |
Here's a version for PHP 5.4 that binds the scope at | |
call time, letting us use $this within the Closure | |
**********************************************************/ | |
trait Call_Dynamic_Methods { | |
public function __call($name, $arguments) { | |
if (isset($this->{$name}) && $this->{$name} instanceof Closure) { | |
$this->{$name} = $this->{$name}->bindTo($this, $this); | |
return call_user_func_array($this->{$name}, $arguments); | |
} | |
return parent::__call($name, $arguments); | |
} | |
} | |
class Foo54 | |
{ | |
use Call_Dynamic_Methods; | |
public $thing = 'blazzoooo'; | |
public function baz($txt) { | |
echo "BAZ: $txt\n"; | |
} | |
} | |
$foo = new Foo54(); | |
$foo->baz('This method was defined in the class'); | |
$foo->bar = function($txt) { echo "BAR: $txt\n"; }; | |
$foo->bar('This method was dynamically added after instantiation'); | |
$foo->bam = function($txt) { echo "BAM: $txt (" . $this->thing . ")\n"; }; | |
$foo->bam('This method was dynamically added after instantiation, and references | |
$this. It will be bound at __call time to set the scope'); | |
$flar = 'poop'; | |
$foo->bal = function($txt) use ($flar) { echo "BAL: $txt (" . $this->thing . ") ($flar)\n"; }; | |
$flar = 'poop2'; | |
$foo->bal('This will output "poop" and not "poop2"'); |
Just for thoroughness - here's the technical reason in a nutshell - remember that properties and methods can have the same names in PHP classes https://gist.github.com/1951282
Appreciate your insights into it, Elizabeth. Ultimately, I think functional languages are a Big Win, and it's always a bummer to come up against the limitations in PHP related to functional programming. Actually making it happen in the existing runtime is, I'm sure, very non-trivial.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Of course the skills can be learned. But learnability is not the only measure of ease.
I agree, all languages have warts. Some warts matter more than others, depending on the individual. PHP fundamentally is missing something I really want, though – first class functions. I am fluent in at least one language that offers this, and I find it extremely useful. That's precisely what I'm running up against here.