The following PHP code results in an error: unexpected T_FUNCTION on the line starting with "say". I'm using PHP version 5.3.6 so lambdas should be supported, but it's not working. I don't know if the "use" clause is valid in this context either, but removing it does not resolve the problem. Is something wrong with my syntax? Note: $this->backend is defined in the constructor as $this->backend = fopen("bar.txt","w+");
class Foo
{
private $backend;
private $commands = array(
0 => array(
"say" => function($msg) use($this->backend) { fwrite($this->backend,$msg); }
)
);
}
Specific to PHP 5.3.x
First off, it's not possible to assign lambdas as default property values (lambdas are not considered a constant expression). So it is not possible to make that assignment directly; you would need to do it inside the constructor.
Secondly, in PHP 5.3.x you cannot use $this inside a lambda. The typical workaround is to make a copy of $this and capture that, as in:
$that = $this;
$func = function() use($that) { ... };
However this way it's not possible to access non-public members of $that from inside the lambda at all, so the technique cannot be used directly in your case.
What you should probably do is store $this->backend in a local variable inside the constructor and use that variable inside the lambda. Both the store and the capture can be done by value or by reference, depending on if you want any modifications to propagate outside the lambda and the possibility that the value of $this->backend may change before the lambda is invoked:
public function __construct() {
$backend = $this->backend;
$this->commands = array(
'say' => function($msg) use($backend) { fwrite($backend, $msg); }
);
}
Later PHP versions
Starting from PHP 5.4.0 you can implicitly use $this inside a lambda defined within a class method:
public function __construct() {
$this->commands = array(
'say' => function($msg) { fwrite($this->backend, $msg); }
);
}
The restriction that lambdas cannot be assigned as default property values still stands.
The problem is
use($this->backend)
$this doesn't exist yet in your class blueprint, so you absolutely can't specify it as this point.
What you're trying to do may be impossible to do inside an anonymous function, as it's not a member of the class as such, and hence doesn't get the $this variable.
You may have to do this in a proper member function of Foo, or pass $this as a parameter.
You cannot define properties in classes directly from variables or as lambda;
// these are incorrect
private $foo = $bar
private $callback = function() ...
// correct
define("BAR", "The bar!");
class A {
private $foo = BAR;
private $commands = array();
...
public function __construct() {
$this->commands[0] = function() ...
Related
Say I'm here:
class Foo
{
public function test()
{
// I'm here!
}
private function pow() {}
}
I want to declare a local variable that references the method $this->pow. I try:
$pow = $this->pow;
This doesn't work:
Notice: Undefined property: Foo::$pow
How do I reference a class instance method in PHP?
I need this because I need to pass the function to an anonymous function inside test. I can't pass $this to the anonymous function because I'm using PHP 5.3, and that only became possible in PHP 5.4. Also, the function pow is not public, so I can't assign $this to an intermediary variable and pass that to the anonymous function.
If pow is public as it is in your example, then you can simply do this:
$self = $this;
$invokePow = function() use ($self) { $self->pow(); };
// ... some time later ...
$invokePow(); // calls pow()
You can also do the same by passing around array($this, 'pow') as a callable and invoking it with call_user_func.
If pow is not public, you are simply out of luck.
However, if you are able to upgrade to 5.4 then it all becomes much easier:
$invokePow = function() { $this->pow(); };
You don't need to capture $this explicitly, and you can invoke $invokePow from any context (even outside the class).
I'm trying to figure out the difference between $_data vs $this->_data
class ProductModel
{
var $_data = null; <--- defined here
function test()
{
$this->_data = <--- but it's accessed using $this
}
}
I know in PHP var is used to define class properties but Why is it accessed using $this. Shouldn't it be like $this->$_data ? What's OOP concept is being used here ? Is it a PHP specific?
PHP along with several other popular programming languages such as Java (it's important to note that PHP's Object Oriented choices were at least partially inspired by Java) refer to the current object instance in context as this. You can think of this, (or $this in PHP) as the "current object instance."
Inside of class methods, $this refers to the current object instance.
A very small example using what you have above:
$_data = 'some other thing';
public function test() {
$_data = 'something';
echo $_data;
echo $this->_data;
}
The above will output somethingsome other thing. Class members are stored along with the object instance, but local variables are only defined within the current scope.
No, it shouldn't. Since PHP can evaluate member names dynamically, the line
$this->$_data
refers to a class member, which name is specified in local $data variable. Consider this:
class ProductModel
{
var $_data = null; <--- defined here
function test()
{
$member = '_data';
$this->$member = <--- here you access $this->_data, not $this->member
}
}
var $_data defines a class variable, $this->_data accesses it.
If you do $this->$foo it means something else, just like $$foo : if you set $foo = 'bar', those two expressions are respectively evaluated as $this->bar and $bar
I would like to assign a static function to a variable so that I can send it around as a parameter. For example:
class Foo{
private static function privateStaticFunction($arg1,$arg2){
//compute stuff on the args
}
public static function publicStaticFunction($foo,$bar){
//works
$var = function(){
//do stuff
};
//also works
$var = function($someArg,$someArg2){
//do stuff
};
//Fatal error: Undefined class constant 'privateStaticFunction'
$var = self::privateStaticMethod;
//same error
$var = Foo::privateStaticFunction;
//compiles, but errors when I try to run $var() somewhere else, as expected
//Fatal error: Call to private method Foo::privateStaticMethod() from context ''
$var = function(){
return Foo::privateStaticMethod();
};
}
}
I've tried a few more variations but none of them worked.
I don't even expect this sort of functional hacking to work with PHP but hey, who knows?
Is it possible to do that in PHP or will I need to come up with some hack using eval?
P.S.: LawnGnome on ##php mentioned something about it being possible to do what I want using array('Foo','privateStaticMethod') but I didn't understand what he meant and I didn't press him further as he looked busy.
You want to use call_user_func with an array argument.
$var = array('Foo','privateStaticMethod');
call_user_func($var);
Note that the "private" specifier on that method will make it only callable this way within the Foo class.
call_user_func takes a callable as the first argument. Note that as of PHP 5.2.3, it is possible to avoid the array notation in your case.
Static class methods can also be passed without instantiating an
object of that class by passing the class name instead of an object at
index 0. As of PHP 5.2.3, it is also possible to pass
'ClassName::methodName'.
As a note, you should set your static variable as so:
static $privateStaticMethod;
$var = self::$privateStaticMethod;
Leaving off a $ when using self:: will try to access a class CONSTANT and not a variable.
In actuality, I think you meant this line to be:
//Fatal error: Undefined class constant 'privateStaticFunction'
$var = self::privateStaticFunction("arga", "argb");
If you are on PHP 5.4 you can do the following within your publicStaticFunction:
$var = function(){
return self::privateStaticFunction();
};
$var();
Within PHP 5.4, PHP allows you to access class scope from lambda functions.
Also, have you looked into ReflectionClass?
The following would be used to replace call_user_func_array() in a more OOP style:
<?php
$rc = new ReflectionClass('SomeClass');
$class = $rc->newInstanceArgs(array('foo', 'bar'));
echo $class->doSomething();
You could write your own class to use ReflectionMethod which implements ReflectionClass and use setAccessible() to allow access to protected and private methods.
Here is what I did to solve my issue
class test{
static function Unix($arr){return implode("/",$arr);}
static function Windows($arr){return implode("\\",$arr);}
function test(){
$slash = "Unix";
echo self::$slash(["path","to","a","folder"]);
}
}
here is an example class:
public class example
{
private $foof;
public function __construct()
{
$this->foof = $this->foo;
}
public function foo($val=0)
{
// do something...
}
}
So basically, in the constructer of the sample code, is it possible to assign a class method to a variable?
Ultimately what i want is to have an associative array with all the class methods aliased in it...that possible in php?
In PHP5.3+ (which you should be using anyway!) you can simply create an anonymous function which calls your method:
$this->foof = function() {
$this->foo(1);
};
However, you cannot call it using $this->foof() - you have to assign it to a variable first: $foof = $this->foof; $foof();
In older PHP versions you cannot easily do this - create_function() does not create a closure so $this is not available there.
You don't need to use anonymous functions. Just use the Callable pseudo type.
$this->foof = array($this, 'foo');
...
call_user_func($this->foof);
The PHP manual states
It is not possible to use $this from anonymous function before PHP
5.4.0
on the anonymous functions page. But I have found I can make it work by assigning $this to a variable and passing the variable to a use statement at the function definition.
$CI = $this;
$callback = function () use ($CI) {
$CI->public_method();
};
Is this a good practice?
Is there a better way to access $this inside an anonymous function using PHP 5.3?
It will fail when you try to call a protected or private method on it, because using it that way counts as calling from the outside. There is no way to work around this in 5.3 as far as I know, but come PHP 5.4, it will work as expected, out of the box:
class Hello {
private $message = "Hello world\n";
public function createClosure() {
return function() {
echo $this->message;
};
}
}
$hello = new Hello();
$helloPrinter = $hello->createClosure();
$helloPrinter(); // outputs "Hello world"
Even more, you will be able to change what $this points to at runtime, for anonymus functions (closure rebinding):
class Hello {
private $message = "Hello world\n";
public function createClosure() {
return function() {
echo $this->message;
};
}
}
class Bye {
private $message = "Bye world\n";
}
$hello = new Hello();
$helloPrinter = $hello->createClosure();
$bye = new Bye();
$byePrinter = $helloPrinter->bindTo($bye, $bye);
$byePrinter(); // outputs "Bye world"
Effectively, anonymus functions will have a bindTo() method, where the first parameter can be used to specify what $this points to, and the second parameter controls what should the visibility level be. If you omit the second parameter, the visibility will be like calling from the "outside", eg. only public properties can be accessed. Also make note of the way bindTo works, it does not modify the original function, it returns a new one.
Don't always rely on PHP to pass objects by reference, when you are assigning a reference itself, the behavior is not the same as in most OO languages where the original pointer is modified.
your example:
$CI = $this;
$callback = function () use ($CI) {
$CI->public_method();
};
should be:
$CI = $this;
$callback = function () use (&$CI) {
$CI->public_method();
};
NOTE THE REFERENCE "&" and $CI should be assigned after final calls on it has been done, again else you might have unpredictable output, in PHP accessing a reference is not always the same as accessing the original class - if that makes sense.
http://php.net/manual/en/language.references.pass.php
That is the normal way it was done.
b.t.w, try to remove the & it should work without this, as objects pass by ref any way.
That seems alright if your passing by reference it's the correct way to do it. If your using PHP 5 you don't need the & symbol before $this as it will always pass by reference regardless.
This is fine. I should think you could do this also:
$CI = $this;
... since assignations involving objects will always copy references, not whole objects.