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';
}
Related
I have a question about variable declare in PHP, I know this question may be little bit stupid. I have the following code
<?php
Class Test{
function __construct(){
$this->test = 'helloworkd';
}
function test(){
echo $this->test;
}
}
$test = new Test();
$test->test();
It seems like I can use the test variable without declaring it. My question is why the test() method can access the test variable? Is the test a global variable?
Thanks for your help!
My question is why the test() method can access the test variable?
PHP unlike some other languages allows you to assign values to variables without first declaring them. The interpreter will initialize them for you. This is poor practice because it makes code harder to read and debug, and because it can cause errors if you try to read a variable that was never declared:
<?php
$nonexistentArray['key'] = 7; //Bad practice, but PHP won't complain
$a = $fakeArray['key']; //Undefined variable error
Even in the second case, PHP will continue to execute the rest of the script, but it will complain.
Is the test a global variable?
No. It lives in the local scope.
<?php
function myFunc(){
//$arr was never declared, but PHP won't complain
$arr['key'][]=7;
}
myFunc();
//Undefined var error. The $arr that was initialized in myFunc is not global
print_r($arr);
A good IDE will complain if you try to use a variable that you never declared. In your case, when in the constructor you do:
$this->test = 'helloworkd';
PHP will initialize this class property for you. Now the rest of your code can use it, including the test() method. If it seems like a global var, it's not. It's a class property. If you tried to access it as just test from outside the class, you would not be able to. You'd have to use the accessor operator -> in $test->test or $this->test.
Many "test"! You have asign test="helloworld" in the contructor, so it takes a value for every new Test() is made.
$x = new Test();
$y = new Test();
echo $x->test(); //"helloworld"
echo $y->test(); //"helloworld"
I would declare your variable. This makes the code more readable for yourself any any others that see your code.
For example:
<?php
Class Test {
public $test;
function __construct($test){
$this->test = $test;
}
function test(){
echo $this->test;
}
So now we have a public variable that is accessible through an instance of this class by calling
$instance->test;
If you do not want this then you can change public to private or protected
You can read about this here: http://php.net/manual/en/language.variables.scope.php
Whatever you pass as an argument when creating an instance of this class will be assigned to the $test variable.
My question is why the test() method can access the test variable?
It can't. It is trying to access a constant test, if you want to access the class variable, use $this->test.
For example:
<?php
echo foo;
Will echo out a string "foo" and also spits out a notice: Use of undefined constant foo - assumed 'foo' in ...
<?php
class test{
public $test;
public function __construct(){
$this->test = 'helloworkd';
}
$newtest = new Test();
echo $newtest->test;
?>
I've tried searching for this but frankly I don't know what to search for and unfortunately I imagine this question has been asked before.
In PHP, and possibly other languages, why can't I use an object immediately after I create it?
// This causes an error
$obj = new Object()->myFunction();
Note: I return $this in most of my setter functions so I can chain them together
function myFunction() {
// ... some more code here ...
return $this;
}
It's simply invalid syntax in PHP. You are able to get this to work in PHP 5.4 by wrapping the object constructor expression with parentheses:
$obj = (new Object())->myFunction();
See PHP 5.4 new features:
Class member access on instantiation has been added, e.g. (new Foo)->bar().
If you want $obj to be the value of the new Object, be sure to return $this from Object::myFunction() (this is called method chaining).
An alternative for getting constructor chaining to work is to have a static method in your class which creates the new class instance for you:
class Object {
public function __construct($var) {
$this->var = $var;
}
public static function newObject($var) {
return new Object($var);
}
}
$obj = Object::newObject()->chainMethodX()->chainMethodY()->...
This is invalid syntax.
PHP only supports:
$obj = new Object();
$obj->myFunction();
Keep in mind that, were you code sample to work, $obj would get the return value of myFunction().
Although not documented on the site it would appear as though the object operator -> has a higher precedence then the new keyword. So saying:
$obj = new Object()->someFunction();
is evaluated like you wrote
$obj = new (Object()->someFunction());
instead of the intended
$obj = (new Object())->someFunction();
The real reason it works this way is in the php grammer definition on line 775
Take the following code as an example:
class xpto
{
public function __get($key)
{
return $key;
}
}
function xpto()
{
static $instance = null;
if (is_null($instance) === true)
{
$instance = new xpto();
}
return $instance;
}
echo xpto()->haha; // returns "haha"
Now, I'm trying to archive the same result but without have to write the xpto class. My guess is I should have to write something like this:
function xpto()
{
static $instance = null;
if (is_null($instance) === true)
{
$instance = new stdClass();
}
return $instance;
}
echo xpto()->haha; // doesn't work - obviously
Now, is it possible to add __get() magic functionality to the stdClass object? I guess not, but I'm not sure.
No, it is not possible. You cannot add anything to stdClass. Also, unlike Java, where every object is a direct or indirect subclass of Object, this is not the case in PHP.
class A {};
$a = new A();
var_dump($a instanceof stdClass); // will return false
What are you really trying to achieve? Your question sounds a bit like "I want to close the door of my car, but without having a car" :-).
The OP looks like they are trying to achieve a singleton pattern using a function in the global scope which is probably not the correct way to go, but anyway, regarding Cassy's answer, "You cannot add anything to stdClass" - this is not true.
You can add properties to the stdClass simply by assigning a value to them:
$obj = new stdClass();
$obj->myProp = 'Hello Property'; // Adds the public property 'myProp'
echo $obj->myProp;
However, I think you need PHP 5.3+ in order to add methods (anonymous functions / closures), in which case you might be able to do something like the following. However, I've not tried this. But if this does work, can you do the same with the magic __get() method?
UPDATE: As noted in the comments, you cannot dynamically add methods in this way. Assigning an anonymous function (PHP 5.3+) does just that and simply assigns a function (strictly a closure object) to a public property.
$obj = new stdClass();
$obj->myMethod = function($name) {echo 'Hello '.$name;};
// Fatal error: Call to undefined method stdClass::myMethod()
//$obj->myMethod('World');
$m = $obj->myMethod;
$m('World'); // Output: Hello World
call_user_func($obj->myMethod,'Foo'); // Output: Hello Foo
I have built a class in PHP and I must declare a class variable as an object. Everytime I want to declare an empty object I use:
$var=new stdClass;
But if I use it to declare a class variable as
class foo
{
var $bar=new stdClass;
}
a parse error occurs. Is there a way to do this or must I declare the class variable as an object in the constructor function?
PS: I'm using PHP 4.
You can only declare static values this way for class members, i.e. ints, strings, bools, arrays and so on. You can't do anything that involves processing of any kind, like calling functions or creating objects.
You'll have to do it in the constructor.
Relevant manual section:
In PHP 4, only constant initializers for var variables are allowed. To initialize variables with non-constant values, you need an initialization function which is called automatically when an object is being constructed from the class. Such a function is called a constructor (see below).
Classes and Objects (PHP 4). A good read everytime!
You should not create your object here.
You should better write setter and getter
<?php
class foo
{
var $bar = null;
function foo($object = null)
{
$this->setBar($object);
}
function setBar($object = null)
{
if (null === $object)
{
$this->bar = new stdClass();
return $this;
}
$this->bar = $object;
return $this;
}
}
By the way, you should use PHP5 to work with OOP, which is more flexible...
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"));