Instancing an object and calling a method in one line? - php

php 5.3
Is there a way to do this (viable in java for example)
(new MyClass())->myMethod();
i am receving: Parse error: syntax error, unexpected T_OBJECT_OPERATOR in D.. on line 7
Add
I really need that RFC to be implemented in the next PHP version!
http://wiki.php.net/rfc/instance-method-call
Is there a way we can subscribe to it so it can get more attention?

No, its not possible. There is a RFC for that
http://wiki.php.net/rfc/instance-method-call
But no one knows, when this will come to the userland.
Jacob mentioned the static method. There are other more or less useful methods to achieve the same
function instanciate($className, $arg1 = null) {
$args = func_get_args();
array_shift($args);
$c = new ReflectionClass($className);
return $c->newInstanceArgs($c);
}
instanciate('Classname', 1, 2, 3)->doSomething();
However, I prefer the temporary variable (like in the question).
Update:
I can swear there where an example for the temporary variable stuff in the question in the past. However, I meant this
$x = new Class;
$x->method();
where $x is the temporary variable.

That is not valid syntax. A handy way to achieve what you want is to use a static method to create the object.
In your MyClass:
public static function create() {
return new MyClass();
}
Then you can use:
MyClass::create()->myMethod();
However it is extra code that you have to maintain, if for example the constructor is changed or the class is extended. So you need to weigh up the benefits.

You can do something like this:
function chain_statements($statement1, $statement2) { return $statement2; }
class TClass { public Method() { ...; return $this; } }
$b = chain_statements($a = new TClass(), $a->Method());
... or more generalized:
function chain_statements(array $statements) { return end($statements); }
For example:
function chain_statements($statement1, $statement2) { return $statement2; }
function chain_statements2(array $statements) { return end($statements); }
class TClass
{
public $a = 0;
public function Method1() { $this->a = $this->a + 1; return $this; }
public function Method2() { $this->a = $this->a + 2; return $this; }
}
$b = chain_statements($c = new TClass(), $c->Method1()); echo($b->a);
$b = chain_statements2(array($c = new TClass(), $c->Method1(), $c->Method2())); echo($b->a);
... or even better:
function call_method($object) { return $object; }
$b = call_method(new TClass())->Method2(); echo($b->a);

Not as such. In PHP new is not an expression, but a language construct. The common workaround is to provide a static instantiation method for MyClass::get()->... use.
A more concise alternative is a hybrid factory function:
function MyClass() { return new MyClass; }
class MyClass {
...
}
Which then simplifies the instantiation to MyClass()->doSomething();

You can put it in one statement if you really wanted to. Use eval() ;p
But you probably shouldn't.

I had this same problem a while ago but I found this simple solution which is pretty readable too. I like the fact it uses only the standard PHP functions. There's no need to create any utility functions of your own.
call_user_func(
array(new ClassToInstance(), 'MethodName'),
'Method arguments', 'go here'
);
You can also use call_user_func_array to pass the arguments as an array.
call_user_func_array(
array(new ClassToInstance(), 'MethodName'),
array('Method arguments', 'go here')
);

Related

Calling member function on array

I don't truly understand how chaining functions work on the values that are returned.
Let's say I have a function that returns a string or array
public static $query;
public static function getArray($arr) {
Database::$query = $arr;
return Database::$query;
}
public function single() {
return Database::$query[0];
}
Why, when I call it can I then not chain a function onto this to affect the string (In this example I was to append ' test' and how would I go about doing this?
Why can I simply not call
Database::getArray(array("test","test2"))->single();
Without getting a Call to a member function single() on array error. But instead, make it return only the first value of the array.
How would I go append doing what I'm trying to achieve here? Why is my logic wrong?
When you call a method, the return value is whatever that method decides to return; the return value doesn't have any automatic relationship with the object you called the method on. For instance:
class A {
public function foo() {
return 'Hello, World!';
}
}
$a = new A;
echo $a->foo();
The value returned is just an ordinary string, just as if foo was a global function not attached to any object.
In PHP, strings (and other "basic types" like arrays) are not objects, so you can't call any methods on them. Even if you could, those methods would be built into the language, and you couldn't just decide that ->single() could be called on any array.
What may be confusing is that some people write methods with the convention that they return an object, known as a "fluent interface", or more generally "chained methods". This is not a feature of the language, just a natural consequence of returning an object from a method:
class A {
public function foo() {
return new B;
}
}
class B {
public function bar() {
return 'Hello, World!';
}
}
$a = new A;
$b = $a->foo(); // $b is a B object
echo $b->bar();
// We can combine this into one line:
echo (new A)->foo()->bar();
There is nothing special about this chaining; it's just that wherever you have an object, you can call appropriate methods on it, just as wherever you have a number, you can do maths with it. Compare with a simple addition:
function foo() {
return 1;
}
$a = foo();
$a = $a + 2;
echo $a;
// We can combine this into one line:
echo foo() + 2;
// Or keep the assignment:
$a = foo() + 2;
echo $a;
The object doesn't know it's being chained - in fact, it shouldn't need to know anything about the code around it, and that's an important part of structured programming.
A common pattern is then to have modifying methods which return the object they just modified, so you can make a series of modifications in one go:
class A {
private $words = [];
public function addWord($word) {
$this->words[] = $word;
// $this is the current object, which is an instance of class A
return $this;
}
public function getString() {
return implode(' ', $this->words);
}
}
$a = new A;
// Calling $a->addWord(...) gives us back the same object
$a = $a->addWord('Hello');
$a = $a->addWord('World');
// Calling $a->getString() gives us back a string
echo $a->getString();
// We can combine this into one line:
echo (new A)->addWord('Hello')->addWord('World')->getString();
Note that you can only refer to $this if you have created an instance of the object (with the new keyword), not in a method declared as static. A static method can still have this kind of pattern, but it will need to return some other object, like new self (a new instance of the current class) or self::$foo (an object created earlier).
it's called fluent interface, if you want to chain methods from same class you have to return this from each of them which you want to call fluently, so your code should look like:
public static $query;
public function getArray($arr) {
Database::$query = $arr;
return $this;
}
public function single() {
return Database::$query[0];
}
after applying changes, the construct Database::getArray(array("test","test2"))->single(); will work, however you may consider renaming method getArray, because as its name suggests, it shouldn't be returning $this, but array
#EDIT
you should change the type of function getArray from public static function to public function to make it work, also your final statement will change to something like:
(new Database())->getArray(array("test","test2"))->single();
however, in this case, I would consider redesigning your class and creating some kind of singleton so that you instantiate Database class only once and store the object somewhere

Is there any cleaner way to call a clouse property in PHP [duplicate]

I would like to be able to call a closure that I assign to an object's property directly without reassigning the closure to a variable and then calling it. Is this possible?
The code below doesn't work and causes Fatal error: Call to undefined method stdClass::callback().
$obj = new stdClass();
$obj->callback = function() {
print "HelloWorld!";
};
$obj->callback();
As of PHP7, you can do
$obj = new StdClass;
$obj->fn = function($arg) { return "Hello $arg"; };
echo ($obj->fn)('World');
or use Closure::call(), though that doesn't work on a StdClass.
Before PHP7, you'd have to implement the magic __call method to intercept the call and invoke the callback (which is not possible for StdClass of course, because you cannot add the __call method)
class Foo
{
public function __call($method, $args)
{
if(is_callable(array($this, $method))) {
return call_user_func_array($this->$method, $args);
}
// else throw exception
}
}
$foo = new Foo;
$foo->cb = function($who) { return "Hello $who"; };
echo $foo->cb('World');
Note that you cannot do
return call_user_func_array(array($this, $method), $args);
in the __call body, because this would trigger __call in an infinite loop.
You can do this by calling __invoke on the closure, since that's the magic method that objects use to behave like functions:
$obj = new stdClass();
$obj->callback = function() {
print "HelloWorld!";
};
$obj->callback->__invoke();
Of course that won't work if the callback is an array or a string (which can also be valid callbacks in PHP) - just for closures and other objects with __invoke behavior.
As of PHP 7 you can do the following:
($obj->callback)();
Since PHP 7 a closure can be called using the call() method:
$obj->callback->call($obj);
Since PHP 7 is possible to execute operations on arbitrary (...) expressions too (as explained by Korikulum):
($obj->callback)();
Other common PHP 5 approaches are:
using the magic method __invoke() (as explained by Brilliand)
$obj->callback->__invoke();
using the call_user_func() function
call_user_func($obj->callback);
using an intermediate variable in an expression
($_ = $obj->callback) && $_();
Each way has its own pros and cons, but the most radical and definitive solution still remains the one presented by Gordon.
class stdKlass
{
public function __call($method, $arguments)
{
// is_callable([$this, $method])
// returns always true when __call() is defined.
// is_callable($this->$method)
// triggers a "PHP Notice: Undefined property" in case of missing property.
if (isset($this->$method) && is_callable($this->$method)) {
return call_user_func($this->$method, ...$arguments);
}
// throw exception
}
}
$obj = new stdKlass();
$obj->callback = function() { print "HelloWorld!"; };
$obj->callback();
It seems to be possible using call_user_func().
call_user_func($obj->callback);
not elegant, though.... What #Gordon says is probably the only way to go.
Well, if you really insist. Another workaround would be:
$obj = new ArrayObject(array(),2);
$obj->callback = function() {
print "HelloWorld!";
};
$obj['callback']();
But that's not the nicest syntax.
However, the PHP parser always treats T_OBJECT_OPERATOR, IDENTIFIER, ( as method call. There seems to be no workaround for making -> bypass the method table and access the attributes instead.
I know this is old, but I think Traits nicely handle this problem if you are using PHP 5.4+
First, create a trait that makes properties callable:
trait CallableProperty {
public function __call($method, $args) {
if (property_exists($this, $method) && is_callable($this->$method)) {
return call_user_func_array($this->$method, $args);
}
}
}
Then, you can use that trait in your classes:
class CallableStdClass extends stdClass {
use CallableProperty;
}
Now, you can define properties via anonymous functions and call them directly:
$foo = new CallableStdClass();
$foo->add = function ($a, $b) { return $a + $b; };
$foo->add(2, 2); // 4
well, it should be emphisized that storing the closure in a variable, and call the varible is actually (wierdly) faster, depending on the call amount, it becomes quite a lot, with xdebug (so very precise measuring), we are talking about 1,5 (the factor, by using a varible, instead of directly calling the __invoke. so instead , just store the closure in a varible and call it.
Here's another alternative based on the accepted answer but extending stdClass directly:
class stdClassExt extends stdClass {
public function __call($method, $args)
{
if (isset($this->$method)) {
$func = $this->$method;
return call_user_func_array($func, $args);
}
}
}
Usage example:
$foo = new stdClassExt;
$foo->blub = 42;
$foo->whooho = function () { return 1; };
echo $foo->whooho();
You are probably better off using call_user_func or __invoke though.
Updated:
$obj = new stdClass();
$obj->callback = function() {
print "HelloWorld!";
};
PHP >= 7 :
($obj->callback)();
PHP >= 5.4 :
$callback = $obj->callback;
$callback();
If you're using PHP 5.4 or above you could bind a callable to the scope of your object to invoke custom behavior. So for example if you were to have the following set up..
function run_method($object, Closure $method)
{
$prop = uniqid();
$object->$prop = \Closure::bind($method, $object, $object);
$object->$prop->__invoke();
unset($object->$prop);
}
And you were operating on a class like so..
class Foo
{
private $value;
public function getValue()
{
return $this->value;
}
}
You could run your own logic as if you were operating from within the scope of your object
$foo = new Foo();
run_method($foo, function(){
$this->value = 'something else';
});
echo $foo->getValue(); // prints "something else"
I note that this works in PHP5.5
$a = array();
$a['callback'] = function() {
print "HelloWorld!";
};
$a['callback']();
Allows one to create a psuedo-object collection of closures.

Class variables holding a function in PHP

PHP allows for variables to hold functions like so:
$f = function($a,$b) {
print "$a $b";
};
$f("Hello","World!"); //prints 'Hello World!'
This works just fine for me. I'm trying to pass a function into a class and set an instance variable to hold that function but with little luck:
class Clusterer {
private $distanceFunc;
public function __construct($f) {
$this->distanceFunc = $f;
print $f(1,7); //works
print $this->distanceFunc(1,7); //exceptions and errors abound
}
}
$func = function($a,$b) {
return abs($a-$b);
}
$c = new Clusterer($func);
Am I doing something wrong here? The error is that the function doesn't exist so my guess currently is that it looks for a class function with that name (which there isn't one) and then gives up rather than looking for variables as well... how can I make it view the $this->distanceFunc as a variable?
EDIT:
So after the advice from the answers below, I found a solution which was the make a function to wrap the invocation. For example my class is now:
class Clusterer {
private $distanceFunc;
public function __construct($f) {
$this->distanceFunc = $f;
print $f(1,7); //works
print $this->distanceFunc(1,7); //exceptions and errors abound
}
private function distanceFunc($a,$b) {
$holder = $this->distanceFunc;
return $holder($a,$b);
}
}
$func = function($a,$b) {
return abs($a-$b);
}
$c = new Clusterer($func);
and this works great. Php looks for functions first and can only tell if it is a variable by context I guess is the moral of this story.
Your code doesn't work because PHP interprets $this->distanceFunc(1,7) as a class method, but you can do the following:
class Clusterer {
private $distanceFunc;
public function __construct($f) {
$this->distanceFunc = $f;
print $f(1,7); //works
print call_user_func_array($this->distanceFunc, array(1, 7));
// print $this->distanceFunc(1,7); //exceptions and errors abound
}
}
$func = function($a,$b) {
return abs($a-$b);
};
$c = new Clusterer($func);
http://sandbox.onlinephpfunctions.com/code/cdc1bd6bd50f62d5c88631387ac9543368069310
In PHP, methods and properties of an object occupy separate namespaces. This is different from JavaScript, for example, where foo.bar = function() {} is a perfectly valid way of defining a method.
Consequently, $this->distanceFunc(1,7); looks for a method named distanceFunc on the current class, and the classes it inherits from, but never looks for the property which you happen to have given the same name.
One solution is to force PHP to look up a property, then execute it, e.g. $foo = $this->distanceFunc; $foo(1,7) or call_user_func($this->distanceFunc, 1, 7)
Another would be to define the magic method __call on your class, which gets run whenever a non-existent method is referenced. Something like this ought to work (I don't have an easy way to testright now):
function __call($func, $args) {
if ( property_exists($this, $func) && is_callable($this->$func) ) {
return call_user_func_array($this->$func, $args);
}
}
Note that this still isn't the same as a real method, for instance in terms of access to private properties.
It looks like you're going for a strategy pattern here. IE you want to be able to inject different methods for calculating distance? If so there is a more "sane" way to do it.
You can define an interface to the classes you will use to store the strategy method ensuring that the class will always have the method calculate() for example which would be your distance calculation function. Then in the constructor of your Clusterer class, type check against the interface in the parameter and call calculate() on the object passed in.
Looks like this:
interface Calculateable
{
public function calculate();
}
class MyDistanceCalculator implements Calculateable
{
public function calculate()
{
// Your function here
}
}
class Clusterer
{
protected $calc;
public function __construct(Calculateable $calc)
{
$this->calc = $calc;
$this->calc->calculate();
}
}
$myClusterer = new Clusterer(new MyDistanceCalculator());
Because you defined an interface, any object you pass in will have the calculate() function
In HHVM, you can do this:
<?php
class Foo
{
public function __construct()
{
$this->bar = function() { echo "Here\n"; };
($this->bar)();
}
}
new Foo();
But it's not yet supported in PHP. But, it will be in PHP 7 (there will be no release named PHP 6).
PHP doesn't have first class functions. In JavaScript if you returned a function you could do this: myFunctionThatReturnsAFunction()(1,2), but not in PHP.
<?php
class Clusterer {
private $distanceFunc;
public function __construct(Closure $f) {
$this->distanceFunc = $f;
}
public function getDistFunc()
{
return $this->distanceFunc;
}
}
$func = function($a,$b) {
return abs($a-$b);
};
$c = new Clusterer($func);
$a = $c->getDistFunc();
echo $a(1,2);
Take a look at call_user_func
class Clusterer {
private $distanceFunc;
public function __construct($f) {
$this->distanceFunc = $f;
print $f(1,7); //works
print call_user_func($this->distanceFunc, 1, 7); //works too ;)
}
}
$func = function($a,$b) {
return abs($a-$b);
};
$c = new Clusterer($func);
Don't ask me what is the difference, but it works the way you want (One of the reasons i hate this language)

Is it possible to use mixins in php

I came to know about mixins.So my doubt is, is it possible to use mixins in php?If yes then how?
Use Trait introduced in PHP 5.4
<?php
class Base {
public function sayHello() {
echo 'Hello ';
}
}
trait SayWorld {
public function sayHello() {
parent::sayHello();
echo 'World!';
}
}
class MyHelloWorld extends Base {
use SayWorld;
}
$o = new MyHelloWorld();
$o->sayHello();
?>
which prints Hello World!
http://php.net/manual/en/language.oop5.traits.php
This answer is obsolete as of PHP 5.4. See Jeanno's answer for how to use traits.
It really depends on what level of mixins you want from PHP. PHP handles single-inheritance, and abstract classes, which can get you most of the way.
Of course the best part of mixins is that they're interchangeable snippets added to whatever class needs them.
To get around the multiple inheritance issue, you could use include to pull in snippets of code. You'll likely have to dump in some boilerplate code to get it to work properly in some cases, but it would certainly help towards keeping your programs DRY.
Example:
class Foo
{
public function bar( $baz )
{
include('mixins/bar');
return $result;
}
}
class Fizz
{
public function bar( $baz )
{
include('mixins/bar');
return $result;
}
}
It's not as direct as being able to define a class as class Foo mixin Bar, but it should get you most of the way there. There are some drawbacks: you need to keep the same parameter names and return variable names, you'll need to pass other data that relies on context such as func_get_args_array or __FILE__.
Mixins for PHP (PHP does not implement Mixins natively, but this library will help)
First google result for "php5 mixin": http://www.sitepoint.com/forums/php-application-design-147/ruby-like-mixins-php5-332491.html
First google result for "php mixin": http://www.advogato.org/article/470.html
Short answer: yes, but not natively (yet, evidently, as #mchl notes). Check those out.
Longer answer: if you're using runkit, checkout runkit_method_copy(): "Copies a method from class to another."
I based mixins functionality on the blog entry found at jansch.nl.
class Node
{
protected $__decorator_lookup = array();
public function __construct($classes = array())
{
foreach($classes as $class)
if (class_exists($class))
{
$decorator = new $class($this);
$methods = get_class_methods($decorator);
if (is_array($methods))
foreach($methods as $method)
$this->__decorator_lookup[strtolower($method)] = $decorator;
}
else
trigger_error("Tried to inherit non-existant class", E_USER_ERROR);
}
public function __get($name)
{
switch($name)
{
default:
if ($this->__decorator_lookup[strtolower($name)])
return $this->__call($name);
}
}
public function __call($method, $args = array())
{
if(isset($this->__decorator_lookup[strtolower($method)]))
return call_user_func_array(array($this->__decorator_lookup[strtolower($method)], $method), $args);
else
trigger_error("Call to undefined method " . get_class($this) . "::$method()", E_USER_ERROR);
}
public function __clone()
{
$temp = $this->decorators;
$this->decorators = array();
foreach($temp as $decorator)
{
$new = clone($decorator);
$new->__self = $this;
$this->decorators[] = $new;
}
}
}
class Decorator
{
public $__self;
public function __construct($__self)
{
$this->__self = $__self;
}
public function &__get($key)
{
return $this->__self->$key;
}
public function __call($method, $arguments)
{
return call_user_func_array(array($this->__self, $method), $arguments);
}
public function __set($key, $value)
{
$this->__self->$key = $value;
}
}
class Pretty extends Decorator
{
public function A()
{
echo "a";
}
public function B()
{
$this->b = "b";
}
}
$a = new Node(array("Pretty"));
$a->A(); // outputs "a"
$a->B();
echo($a->b); // outputs "b"
EDIT:
As PHP clone is shallow, added __clone support.
Also, bear in mind that unset WON'T work (or at least I've not managed to make it work) within the mixin. So - doing something like unset($this->__self->someValue); won't unset the value on Node. Don't know why, as in theory it should work. Funny enough unset($this->__self->someValue); var_dump(isset($this->__self->someValue)); will produce correctly false, however accessing the value from Node scope (as Node->someValue) will still produce true. There's some strange voodoo there.

Restricting variable access

I need to have a variable that only one function can write (let's call that function a) and that only one other function can read (let's call that function b). Is that possible?
You could use a static variable:
function foo($val=null) {
static $var = null;
if (!is_null($var)) $var = $val;
return $val;
}
Here $var is only visible inside the function foo and is maintained throughout multiple calls:
foo(123);
echo foo(); // 123
foo(456);
echo foo(); // 456
Or use a class with a private member and access/modify it with public methods:
class A {
private $var;
public function setVar($val) {
$this->var = $val;
}
public function getVar() {
return $this->var;
}
}
With this the private member var is only visible to a particular instance of this class:
$obj1 = new A();
$obj1->setVar(123);
$obj2 = new A();
$obj2->setVar(456);
echo $obj1->getVar(); // 123
echo $obj2->getVar(); // 456
If you make the member static, then there is just one for the class instead of for each instance:
class A {
private static $var;
public function setVar($val) {
self::$var = $val;
}
public function getVar() {
return self::$var;
}
}
$obj1 = new A();
$obj1->setVar(123);
$obj2 = new A();
$obj2->setVar(456);
echo $obj1->getVar(); // 456
echo $obj2->getVar(); // 456
You can use a static abstract class.
abstract class Settings
{
private static var $_settings = array();
public static function get($key,$default = false)
{
return isset(self::$_settings[$key]) ? self::$_settings[$key] : $default;
}
public static function set($key,$value)
{
self::$_settings[$key] = $value;
}
}
Example Usage:
Settings::set('SiteName',`SomeResult`);
echo Settings::get('SiteName');
Since 5.3.0, you can use anonymous functions as closures. The advantage here, is that you can hold on to b... which is returned by a... and fire it off when you're ready:
<?php
function a()
{
// Only a() can write to $myVar
$myVar = 42;
$b = function() use ($myVar)
{
// $b can read $myVar
// no one else can
return $myVar;
};
return $b;
}
// get $b
$test = a();
// use $b
echo $test();
?>
Another solution before 5.3.0, but here a has to fire b which may not be that practical:
You can simply create an internal variable and pass it as an argument. You can do this inside a class, or just inside simple functions:
function a()
{
// ...
// Write the variable that
// only this function can write to
$thisVar = 1;
b($thisVar);
//...
}
function b($myVar)
{
// ...
// Do stuff w $myVar, a copy of $thisVar
// Changing $myVar has no effect on $thisVar
//
}
Do you mean friend functions? Because I'd love to be able to do that. So far I haven't found an easy way though (although you could try using Reflection, but that seems like way to much effort).
For me, it usually hasn't been an issue of maintaining data integrity / encapsulation, but of keeping the list of public methods (which is kinda like a class's API) free of clutter. A perfect framework should be easy to use, have obvious function names etc etc etc. Methods intended for use by a single other method really mess things up. The "solution" I've taken to is prefixing those function names by one or two underscores and writing "intended for internal use only" or something to that extent in the comments.

Categories