Is there a way to set or modify the variable $this in PHP? In my case, I need to call an anonymous function where $this refers to a class that is not necessarily the class that made the call.
Pseudo-example:
function test() {
echo $this->name;
}
$user = new stdclass;
$user->name = "John Doe";
call_user_func(array($user, "test"));
Note: this will generate an error, because, in fact, the function expects an array containing an object and a method that exists in this object, and not any method of global scope.
Why not try setting the function definition to accept an object as a parameter? For example:
function test($object) {
if (isset($object->name)) // Make sure that the name property you want to reference exists for the class definition of the object you're passing in.
echo $object->name;
}
}
$user = new stdclass;
$user->name = "John Doe";
test($user); // Simply pass the object into the function.
The variable $this, when used in a class definition, refers to the object instance of the class. Outside of a class definition (or in a static method definition), variable $this has no special meaning. When you attempt to use $this outside of the OOP pattern, it loses meaning and call_user_func(), which relies on the OOP pattern, will not work in the way that you've attempted.
If you're using functions in a non-OOP way (like global functions), the function is not tied to any class/object and should be written in a non-OOP way (passing in data or otherwise using globals).
You can use the bind method on a closure object to change the meaning of this in a particular context. Note this functionality became available in PHP 5.4.
Official Description
Duplicates a closure with a specific bound object and class scope
class TestClass {
protected $var1 = "World";
}
$a = new TestClass();
$func = function($a){ echo $a." ".$this->var1; };
$boundFunction = Closure::bind($func, $a, 'TestClass');
$boundFunction("Hello");
// outputs Hello World
An alternative to this syntax it to use the bindTo method of an instance of a closure (anonymous function)
class TestClass {
protected $var1 = "World";
}
$a = new TestClass();
$func = function($a){ echo $a." ".$this->var1; };
$boundFunction = $func->bindTo($a, $a);
$boundFunction("Hello");
// outputs Hello World
In your example the relevant code would be
$test = function() {
echo $this->name;
};
$user = new stdclass;
$user->name = "John Doe";
$bound = $test->bindTo($user, $user);
call_user_func($bound);
Related
New to php. I am writing a class and was wondering why some variable $variable does not need a $ when calling $this->variable?
In Object Oriented Programming when you declare variables like so
public $variable;
these are no more variables but are the properties of the object of the class.
So when we call these properties we reference these through $this->property Which means that we are calling the property of the present object. $this refers to the instance of the present class. Whenever you would call properties and methods within class you have to use $this->property-or-method.
It is not the variable. It means object oriented.
It's a reference to the current object, it's most commonly used in object oriented code.
Reference: http://www.php.net/manual/en/language.oop5.basic.php
Primer:http://www.phpro.org/tutorials/Object-Oriented-Programming-with-PHP.html
Example:
<?php
class Person {
public $name;
function __construct( $name ) {
$this->name = $name;
}
};
$jack = new Person('Jack');
echo $jack->name;
This stores the 'Jack' string as a property of the object created.
Because that variable is inside a larger variable called an Object and the object knows how to access it's inner variables / functions. Like a smart-variable.
Objects can be used to group data or similar functions (called method's when they are inside of an object)
For data/values, you could also use an array. It's common to see data stored in objects as well.
But you wouldn't store functions in an array. In PHP that's a no-go, but in JavaScript that's all good.
Back to objects, functions stored in objects are called methods. Objects can contain methods or properties.
Object Method / Function Example from: http://php.net/manual/en/language.types.object.php
<?php
class foo
{
function do_foo()
{
echo "Doing foo.";
}
}
$bar = new foo;
$bar->do_foo();
// also valid $bar::do_foo();
?>
Object Property / Variable Example From: http://php.net/manual/en/language.oop5.properties.php
<?php
class SimpleClass
{
// valid as of PHP 5.6.0:
public $var1 = 'hello ' . 'world';
// valid as of PHP 5.3.0:
public $var2 = <<<EOD
hello world
EOD;
// valid as of PHP 5.6.0:
public $var3 = 1+2;
// invalid property declarations:
public $var4 = self::myStaticMethod();
public $var5 = $myVar;
// valid property declarations:
public $var6 = myConstant;
public $var7 = array(true, false);
// valid as of PHP 5.3.0:
public $var8 = <<<'EOD'
hello world
EOD;
}
?>
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 have a set of PHP functions that I want to move into a new class. One of the functions is using &$obj in an argument to modify the original object:
function process_new_place_names(&$obj)
any changes made to $obj in this function are passed back to the script.
Question is, can I do this inside a PHP class too? Also, what is the terminology of this approach?
You can absolutely do this inside of classes. It's known as passing by reference.
Further reading:
http://php.net/manual/en/language.references.php
http://php.net/manual/en/language.oop5.references.php
As SomeKittens says, this is perfectly possible inside a class. However, if $obj is itself an instance of a class, and all you need to do is modify its member variables (known as mutating the object) then there's no need to pass it by reference.
For example, the following code will output baz;
class Foo
{
public $bar;
}
function process_new_place_names($obj)
{
$obj->bar = 'baz';
}
$obj = new Foo();
$obj->bar = 'bar';
process_new_place_names($obj);
echo $obj->bar;
Pass-by-reference is only necessary when you want to change the value of the variable itself; for example, re-assigning the object reference:
function process_new_place_names(&$obj)
{
$obj = new Foo();
$obj->bar = 'baz';
}
PHP scripts
register.php:
$compareUser = new User();
$user = new User;
verify.php (executes with a link from register.php, passes two variables to User.php)
User.php
setActive($token, $uid){
$this->username = /????
}
*assuming that User has a username property, which instance of the User class will $this take?
$compareUser or $user?
That depends entirely on which object you call setActive() on. You cannot simply write...
setActive('foo', 'bar');
You must write one of these two:
$compareUser->setActive('foo', 'bar');
$user->setActive('foo', 'bar');
In either case, $this is whichever object you used to invoke that method. That is, in fact, the exact purpose of the $this variable.
class User {
var $username;
function User($name) {
$this->username = $name;
}
function setActive($token, $uid) {
echo $this->username;
}
}
$user1 = new User('tom');
$user2 = new User('sally');
$user1->setActive(1, 2); // tom
$user2->setActive(1, 2); // sally
Make sure setActive is defined in the class definition like in the above. Hopefully the above helps clear things up.
$this is context-sensitive - it always refers to the current context in which code is running.
It is not possible to refer to $this unless you call it from within a (non-static) class method. When you do, $this refers to whichever instance of the class invoked that method upon run-time.
The "without specifying which" part of our initial question is where you're wrong.
As the examples have shown: It is not possible to use an "unspecified" $this, since it is always called from within one certain instance of that class.
Edited to illustrate my comment:
class Foo
{
protected $var;
function _construct( $var )
{
$this->var = $var;
}
function echoVar()
{
// Works since it's within a class and points to an instance's variable:
echo $this->var;
}
}
$first = new Foo( 'first' );
$second = new Foo( 'second' );
// These will work:
$first->echoVar();
$second->echoVar();
// This won't. What's it supposed to show?
$this->echoVar();
I know this question sounds rather vague so I will make it more clear with an example:
$var = 'bar';
$bar = new {$var}Class('var for __construct()'); //$bar = new barClass('var for __construct()');
This is what I want to do. How would you do it? I could off course use eval() like this:
$var = 'bar';
eval('$bar = new '.$var.'Class(\'var for __construct()\');');
But I'd rather stay away from eval(). Is there any way to do this without eval()?
Put the classname into a variable first:
$classname=$var.'Class';
$bar=new $classname("xyz");
This is often the sort of thing you'll see wrapped up in a Factory pattern.
See Namespaces and dynamic language features for further details.
If You Use Namespaces
In my own findings, I think it's good to mention that you (as far as I can tell) must declare the full namespace path of a class.
MyClass.php
namespace com\company\lib;
class MyClass {
}
index.php
namespace com\company\lib;
//Works fine
$i = new MyClass();
$cname = 'MyClass';
//Errors
//$i = new $cname;
//Works fine
$cname = "com\\company\\lib\\".$cname;
$i = new $cname;
How to pass dynamic constructor parameters too
If you want to pass dynamic constructor parameters to the class, you can use this code:
$reflectionClass = new ReflectionClass($className);
$module = $reflectionClass->newInstanceArgs($arrayOfConstructorParameters);
More information on dynamic classes and parameters
PHP >= 5.6
As of PHP 5.6 you can simplify this even more by using Argument Unpacking:
// The "..." is part of the language and indicates an argument array to unpack.
$module = new $className(...$arrayOfConstructorParameters);
Thanks to DisgruntledGoat for pointing that out.
class Test {
public function yo() {
return 'yoes';
}
}
$var = 'Test';
$obj = new $var();
echo $obj->yo(); //yoes
I would recommend the call_user_func() or call_user_func_arrayphp methods.
You can check them out here (call_user_func_array , call_user_func).
example
class Foo {
static public function test() {
print "Hello world!\n";
}
}
call_user_func('Foo::test');//FOO is the class, test is the method both separated by ::
//or
call_user_func(array('Foo', 'test'));//alternatively you can pass the class and method as an array
If you have arguments you are passing to the method , then use the call_user_func_array() function.
example.
class foo {
function bar($arg, $arg2) {
echo __METHOD__, " got $arg and $arg2\n";
}
}
// Call the $foo->bar() method with 2 arguments
call_user_func_array(array("foo", "bar"), array("three", "four"));
//or
//FOO is the class, bar is the method both separated by ::
call_user_func_array("foo::bar"), array("three", "four"));