I am building an API class that extends the functionality of a vendor class. The vendor class expects to be extended, and will check for the existence of methods like this:
if (method_exists($this, 'block'.$CurrentBlock['type']))
{
$CurrentBlock = $this->{'block'.$CurrentBlock['type']}($CurrentBlock);
}
So since my API is also a vendor file, I thought I'd do something clever and try to let people pass closures into my API and have that extend the class.
public function extendBlock($blockName, Closure $closure)
{
$methodName = camel_case("block_{$blockName}");
$this->{$methodName} = $closure;
return method_exists($this, $methodName);
}
This would theoretically bind the closure so that the call in my first codeblock would succeed... but that doesn't happen. It is not seen as a method, but rather a property which contains a closure. Not only does method_exist fail, but attempting to call the method fails.
Here's a modified version where I'm trying to figure out what's going wrong.
public function extendBlock($blockName, Closure $closure)
{
$methodName = camel_case("block_{$blockName}");
$newClosure = clone $closure;
$newClosure = $newClosure->bindTo($this);
$this->{$methodName} = $newClosure;
$this->{$methodName}();
return method_exists($this, $methodName);
}
None of this works. The property is definitely set and the scope for $this in $closure is currently pointing to the $this of that method.
If I run this instead, the closure executes correctly.
$this->{$methodName} = $newClosure;
//$this->{$methodName}();
$foobar = $this->{$methodName};
$foobar();
So yeah. I was really hoping for a nice, tidy way of satisfying the check in my first codeblock without requiring the user to inherit my class and write them directly, but I don't think that's possible.
Edit: This is slightly different from Storing a Closure Function in a Class Property in PHP -- while the solution with __call that was provided there is excellent and is worth looking into if you're curious about binding closures to a class, this method does not trick the method_exists check.
It will not work with method_exists() as that function provides information based on methods which are declared explicitly in the class scope. However, there is still workaround with magic methods. __call() to be precise:
class Caller
{
public function bind($method, Closure $call)
{
$this->$method = $call;
}
public function __call($method, $args)
{
if (isset($this->$method) && $this->$method instanceof Closure) {
return call_user_func_array($this->$method, $args);
}
}
}
Will allow you to force call on your "property callable". For example,
$c = function($x) {
return $x*$x;
};
$obj = new Caller();
$obj->bind('foo', $c);
var_dump($obj->foo(4)); //16
See sample here.
There may be ways to change the class itself dynamically (runkit and company), but I would strongly recommend to stay away from that as long as possible.
With latest Runkit from http://github.com/zenovich/runkit you can simply write runkit_method_add(get_class($this), $methodName, $newClosure);
to do this.
Related
This is an odd situation and I think the answer is 'you can't do that, what are you thinking?' but hope someone can prove me wrong.
My goal is to store a globally scoped function in a variable then inject it for execution within a class object.
I would like to avoid using call_user_func() as this searches for the function in the global namespace and is the same effect as if I were to just execute the global function from within the class object. I would like my class to execute the object as if it were an internal class method, not an external function. This comes close but not quite.
I cannot modify the function or wrap it in a class.
(Why am I jumping through these hoops?) Needs to be used within this class to follow a spec.
I know I can just duplicate the function in the class and be done with it, but you know the issues with that (plus it creeps up on SRP.) Reflection would work perfectly but this function is not in a class, it is just out there in an include. I've tried wrapping it an anonymous function and the closure object doesn't execute the function.
Is there any hope to do this? The function is simple, accepts a scalar param, does some stuff to it, returns a value (and is tightly coupled with other code, cannot be moved or changed.)
function someFunction($param)
{
// do some stuff
return $someScalarValue;
}
What I would hope is something like
$func = someFunction([some value]); // doesn't work of course, this would store result in $func
$cls = new SomeClass($func);
Then a method in the class could run the function object, much like call_user_func but not have to search the global namespace.
protected function someThing()
{
$this->injected_function([some class value]); // also doesn't work of course
}
When you use $this you are in the objects instance scope. You could pass a (reference) method into the constructor.
$myFunc = function($arg) { var_dump($arg); return 314; };
class myClass {
private $func;
public function __construct($func) {
$this->func = $func;
}
public function do($value) {
$this->func->call($this, $value);
}
}
$var = 'Hello world!';
$myObj = new myClass($myFunc);
$value = $myObj->do($var); // $value is now 314
If you do not want the function to be stored in global namespace you can just pass even an anonymous function like this on the fly:
$myObj = new myClass(function($arg) { var_dump($arg); return 314; });
$value = $myObj->do($var); // $value is now 314
Thank you #Markkus Zeller for your comments, as I suspected there is no way to do what I originally was tasked, to "inject" a global function as an dependency. There is, but it only really works with anonymous functions.
After a lot of stressful pushback, I convinced our managers that wrapping this in a simple class was the way to go. This,
// require_once('some-function.php');
function someFunction($param)
{
// do some stuff
return $someScalarValue;
}
. . . now becomes this. (Typed out on the fly and may contain deficiencies, concept only)
// require_once('some-function.php');
require_once('path/to/SomeFunctionClass.php');
function someFunction($param)
{
$cls = new SomeFunctionClass($param);
return $cls->execute();
}
. . . where execute() contains identical code that was in someFunction(). I can now use "SomeFunctionClass" for a DI. There is more to the story, but that is the gist, and this one change can be implemented without modifying any of the 450 or so instances that use this global function (and each of those they can be gradually ported to use the new wrapper.) It also allows me to isolate and mock the functionality for unit testing.
When I'm trying to serialize an object which has members including closures an exception is thrown.
To avoid the serialization of the members including closures I tried the following:
function __sleep(){
$ref = new ReflectionClass($this);
$props = $ref->getProperties();
foreach ($props as $prop){
$name = $prop->name;
if (is_callable($this->$name)===false){
$dream[] = $prop->name;
}
}
return $dream;
}
Unfortunately this does not work. Is there a better way to detect whether a property is a closure or not.
EDIT: I solved my problem by letting the closure know whether to serialize or not
To do this I am wrapping the closure itself. Here's an example:
/**
* Wrapper-class to prevent closure to be serialized.
*/
class WrappedClosure {
private $closure = NULL;
protected $reflection = NULL;
public function __construct($function){
if ( ! $function instanceOf Closure)
throw new InvalidArgumentException();
$this->closure = $function;
$this->reflection = new ReflectionFunction($function);
}
/**
* When the instance is invoked, redirect invocation to closure.
*/
public function __invoke(){
$args = func_get_args();
return $this->reflection->invokeArgs($args);
}
// do nothing on serialization
public function __sleep(){}
// do nothing on serialization
public function __wakeup(){}
}
// Assigning a wrapped closure to a member
$myObject->memberHoldingAClosure =
// Wrapping the closure
new WrappedClosure(
function (){
echo "I'am the inner closure.";
}
)
);
// the serialization doesn't throw an exception anymore
serialize($myObject);
Works fine for me:
class foo {
protected $param = 'value';
protected $closure = null;
public function __construct() {
$this->closure = function(){
return 123;
};
}
public function __sleep() {
$serializable = array();
foreach ( $this as $paramName => $paramValue ) {
if ( !is_string($paramValue) && !is_array($paramValue) && is_callable($paramValue) ) {
continue;
}
$serializable[] = $paramName;
}
return $serializable;
}
}
$foo = new foo();
echo serialize($foo);
About checking if value is instance of Closure class (from manual):
Anonymous functions are currently
implemented using the Closure class.
This is an implementation detail and
should not be relied upon.
Therefore I would implement is_closure($value) function as return !is_string($value) && !is_array($value) && is_callable($value) rather than return $value instanceof Closure and hope that some day PHP developers will add native is_closure() function.
Honestly, I think you're trying to solve the wrong problem. If you're sleeping the class, then isn't it wrong to have a successful sleep if you can't serialize everything? Otherwise you can wake up to an inconsistent state (or at least a state that's different than the current one). So I would argue that you should just put everything into the resultant array and then let PHP tell you if it's not serializable.
Otherwise, do you then need to check to see if any stored objects are serialzable? Should you then be checking for Serializable interface or the existence of __sleep? Where do you draw the line? So I would say that you should only not serialize resources and variables that you explicitly know how to recreate in the wakeup function (such as a database connection, or any closures you explicitly know how to recreate). But be careful here, since if you let those closures/resources be changed via the object's API, how can you be sure of a successful wakeup to the prior state.
So in short, I would recommend just returning everything, and letting PHP handle unserializable variables. Otherwise you'd need to either white-list (which isn't going to be practical) or black-list (which isn't going to be complete). And neither is a great solution. Just handle the exception when it comes (throwing and catching exceptions isn't bad).
As far as your exact question, I would implement it as follows:
function is_closure($callback) {
$func = function(){};
return $callback instanceof $func;
}
It still relies on the implementation detail of the closure being of a Object type, but I think that's the best we can do at this point. The best solution would be to petition the core to add a is_closure() function which would be implementation independent...
I want to create an instance of a class and call a method on that instance, in a single line of code.
PHP won't allow calling a method on a regular constructor:
new Foo()->set_sth(); // Outputs an error.
So I'm using, if I can call it that, a static constructor:
Foo::construct()->set_sth();
Here's my question:
Is using static constructors like that considered a good practice and if yes, how would you recommend naming the methods for these static constructors?
I've been hesitating over the following options:
Foo::construct();
Foo::create();
Foo::factory()
Foo::Foo();
constructor::Foo();
Static constructors (or "named constructors") are only beneficial to prove an intention, as #koen says.
Since 5.4 though, someting called "dereferencing" appeared, which permits you to inline class instantiation directly with a method call.
(new MyClass($arg1))->doSomething(); // works with newer versions of php
So, static constructors are only useful if you have multiple ways to instantiate your objects.
If you have only one (always the same type of arguments and number of args), there is no need for static constructors.
But if you have multiple ways of instantiations, then static constructors are very useful, as it avoids to pollute your main constructor with useless argument checking, weakening languages constraints.
Example:
<?php
class Duration
{
private $start;
private $end;
// or public depending if you still want to allow direct instantiation
private function __construct($startTimeStamp = null, $endTimestamp = null)
{
$this->start = $startTimestamp;
$this->end = $endTimestamp;
}
public static function fromDateTime(\DateTime $start, \DateTime $end)
{
return new self($start->format('U'), $end->format('U'));
}
public static function oneDayStartingToday()
{
$day = new self;
$day->start = time();
$day->end = (new \DateTimeImmutable)->modify('+1 day')->format('U');
return $day;
}
}
As you can see in oneDayStartingToday, the static method can access private fields of the instance! Crazy isn't it ? :)
For a better explanation, see http://verraes.net/2014/06/named-constructors-in-php/
The naming of any method should be with intention revealing names. I can't tell what 'Foo::factory' does. Try to build to a higher level language:
User::with100StartingPoints();
This would be the same as:
$user = new User();
$user->setPointsTo(100);
You could also easily test whether User::with100StartingPoints() is equal to this.
If you don't need a reference to the newly constructed Foo, why don't you simply make set_sth a static function (and have it create a new Foo internally if required)?
If you do need to get hold of the reference, how would you do it? return $this in set_sth? But then set_sth can be made into a factory function anyway.
The only situation I can think of is if you want to call chainable methods (like in a fluent interface) on a newly constructed instance all in one expression. Is that what you are trying to do?
Anyway, you can use a general-purpose factory function for all types of objects, e.g.
function create_new($type) {
return new $type;
}
create_new('Foo')->set_sth();
It's probably not quite a best practice, but you could use the fact that functions and classes have two different namespaces : you can have a function that have the same name as a class.
This allows one to write this kind of code, for example :
function MyClass() {
return new MyClass();
}
class MyClass {
public function __construct() {
$this->a = "plop";
}
public function test() {
echo $this->a;
}
protected $a;
}
Note that I have defined a function called MyClass, and a class with the same name.
Then, you can write this :
MyClass()->test();
Which will work perfectly, and not get you any error -- here, you'll get the following output :
plop
Addition to Jon's answer: To allow constructor arguments use the following:
function create($type) {
$args = func_get_args();
$reflect = new ReflectionClass(array_shift($args));
return $reflect->newInstanceArgs($args);
}
create('Foo', 'some', 'args')->bar();
Documentation: ReflectionClass->newInstanceArgs
These are called creation methods, and I typically name them createXXX() such as createById() or createEmptyCatalog(). Not only do they provide a nice way to reveal the different intentions of an object's constructors, but they enable immediate method chaining in a fluent interface.
echo Html_Img::createStatic('/images/missing-image.jpg')
->setSize(60, 90)
->setTitle('No image for this article')
->setClass('article-thumbnail');
Propel uses a static method "create". I'd go with that. This method makes the code easier to test rather than just using static methods to perform business logic.
<?php
class MyClass
{
public static function create()
{
return new MyClass();
}
public function myMethod()
{
}
}
Besides, you can also pass parameters to the constructor. For instance:
<?php
class MyClass
{
public function __construct($param1, $param2)
{
//initialization using params
}
public static function create($param1, $param2)
{
return new MyClass($param1, $param2); // return new self($param1, $param2); alternative ;)
}
public function myMethod()
{
}
}
In either case, you'd be able to invoke myMethod right after the create method
<?php
MyClass::create()->myMethod();
// or
MyClass::create($param1, $param2)->myMethod();
A bit late to the party but I think this might help.
class MyClass
{
function __construct() {
// constructor initializations here
}
public static myMethod($set = null) {
// if myclass is not instantiated
if (is_null($set)) {
// return new instance
$d = new MyClass();
return $d->Up('s');
} else {
// myclass is instantiated
// my method code goes here
}
}
}
this can then be used as
$result = MyClass::myMethod();
optional parameters can be passed through either the __constructor or myMethod.
This is my first post and I hope I got the gimmicks right
I'm learning Prado php framework for a while now, and I've been wondering about one feature, if it's from PHP or somehow implemented in Prado.
Namely, classes used in Prado can utilize properties (fields) that aren't declared in the class itself, but 'defined' by set and get methods.
Here's an example:
class myClass extends somePradoClass {
public function myPradoMethod() {
$MyVariable = 22;
echo $MyOtherVariable; // this one is read only (only get method defined)
}
public function getMyVariable() {
return 0;
}
public function setMyVariable($value) {
$this->isFieldFromParentClass = $value;
}
public function getMyOtherVariable() {
return $this->isOtherFieldFromParentClass;
}
}
Now, somehow it is perfectly fine to use $MyVariable and $MyOtherVariable throughout the class, as if they were declared as class properties.
So, question again: is this a PHP or Prado feature?
Thx
This is neither a PHP feature nor a Prado feature.
I don't know Prado, but PHP has not such feature, so Prado can't have it either ;)
What you are looking for however, are things such as this: $this->myUndefinedMember = $something
Your example uses local variables, these cannot be set and read from automagically.
This will invoke the magic __set method, if defined that is.
Prado could (I don't know if it does) define this method for a certain superclass that you usually use and then dynamically check whether a setter method has been defined for that variable name.
The signature is as follows:
public function __set($name, $value)
The maigc method __get($name) works analogously.
If you do not set it as public, you will only be able to use this property-like feature from within the class( or subclasses).
As a reference, see here on PHP5's feature or overloading properties and methods.
Update
A sample implementation could look like this:
class MyMagicSuperClass{
public function __get($name){
$getter_name = 'get'.ucwords($name);
if(method_exists($this, $getter_name){
return $this->$getter_name();
}
//error handling
}
public function __set($name, $value){
$setter_name = 'get'.ucwords($name);
if(method_exists($this, $setter_name){
return $this->$setter_name($value);
}
//error handling
}
}
I answer very late to this but I felt the answers posed very confusing to a simple feature.
To give a much simpler answer. Any Prado classes that inherits from TComponent use the __set and __get functions.
More about php magic functions here
So if u have a function that starts with "get" or "set" they will be called when use the rest of the function name as fields.
This is the actual prado code for __get the __set is about the same
public function __get($name)
{
$getter='get'.$name; $jsgetter = 'getjs'.$name;
if(method_exists($this,$getter))
{
// getting a property
return $this->$getter();
}
else if(method_exists($this,$jsgetter))
{
// getting a property
return (string)$this->$jsgetter();
}
else if(strncasecmp($name,'on',2)===0 && method_exists($this,$name))
{
// getting an event (handler list)
$name=strtolower($name);
if(!isset($this->_e[$name]))
$this->_e[$name]=new TList;
return $this->_e[$name];
}
else
{
throw new TInvalidOperationException('component_property_undefined',get_class($this),$name);
}
}
I would like to know whether there's a way to chain methods on a newly created object in PHP?
Something like:
class Foo {
public function xyz() { ... return $this; }
}
$my_foo = new Foo()->xyz();
Anyone know of a way to achieve this?
In PHP 5.4+, the parser's been modified so you can do something like this
(new Foo())->xyz();
Wrap the instantiation in parenthesis, and chain away.
Prior to PHP 5.4, when you're using the
new Classname();
syntax, you can't chain a method call off the instantiation. It's a limitation of PHP 5.3's syntax. Once an object is instantiated, you can chain away.
One method I've seen used to get around this is a static instantiation method of some kind.
class Foo
{
public function xyz()
{
echo "Called","\n";
return $this;
}
static public function instantiate()
{
return new self();
}
}
$a = Foo::instantiate()->xyz();
By wrapping the call to new in a static method, you can instantiate a class with method call, and you're then free to chain off that.
Define a global function like this:
function with($object){ return $object; }
You will then be able to call:
with(new Foo)->xyz();
In PHP 5.4 you can chain off a newly instantiated object:
http://docs.php.net/manual/en/migration54.new-features.php
For older versions of PHP, you can use Alan Storm's solution.
This answer is outdated - therefore want to correct it.
In PHP 5.4.x you can chain a method to a new-call. Let's take this class as example:
<?php class a {
public function __construct() { echo "Constructed\n"; }
public function foo() { echo "Foobar'd!\n"; }
}
Now, we can use this: $b = (new a())->foo();
And the output is:
Constructed
Foobar'd!
Further information may be found on the manual: http://www.php.net/manual/en/migration54.new-features.php
Well, this may be an old question but as with a lot of things in programming - eventually the answer changes.
Regarding PHP 5.3, no, you can't chain directly from the constructor. To expand on the accepted answer however, in order to properly accommodate for inheritance, you can do:
abstract class Foo
{
public static function create()
{
return new static;
}
}
class Bar extends Foo
{
public function chain1()
{
return $this;
}
public function chain2()
{
return $this;
}
}
$bar = Bar::create()->chain1()->chain2();
That will work just fine and will return you a new Bar() instance.
In PHP 5.4, however, you can simply do:
$bar = (new Bar)->chain1()->chain2();
Hopefully this helps someone stumbling across the question like I have!
It would be really helpful if they 'fix this' in a future release. I really appreciate the ability to chain (especially when populating collections):
I added a method to the base class of my framework called create() that can be chained off of. Should work with all descendant classes automatically.
class baseClass
{
...
public final static function create()
{
$class = new \ReflectionClass(get_called_class());
return $class->newInstance(func_get_args());
}
...
public function __call($method, $args)
{
$matches = array();
if (preg_match('/^(?:Add|Set)(?<prop>.+)/', $method, $matches) > 0)
{
// Magic chaining method
if (property_exists($this, $matches['prop']) && count($args) > 0)
{
$this->$matches['prop'] = $args[0];
return $this;
}
}
}
...
}
Class::create()->SetName('Kris')->SetAge(36);
Just for the sake of completeness (and for the fun of it...), since nobody seems to have mentioned the solution with the shortest (and least sophisticated) code.
For frequently used short-lived objects, especially when writing test cases, where you typically do lots of object creation, you may want to optimize for typing convenience (rather than purity), and sorta' combine Alan Storm's Foo::instantiate() factory method and Kenaniah's with() global function technique.
Simply make the factory method a global function with the same name as the class!. ;-o (Either add it as a convenience wrapper around the proper static Foo::instantiate() or just move it out there while nobody is looking.)
class Foo
{
public function xyz()
{
echo "Called","\n";
return $this;
}
}
function Foo()
{
return new Foo();
}
$a = Foo()->xyz();
NOTE:
I WOULDN'T DO THIS on production code. While kinda' sexy, this is an abuse on basic coding principles (like "principle of least surprise" (although this is actually rather intuitive syntax), or "don't repeat yourself", esp. if wrapping a real factory method with some parameters, which itself, BTW, is already an abuse of DRY...), plus PHP may change in he future to break code like this in funny ways.