In the minutes php6 developer meeting, i came across a point where it said that call-time-pass-by-reference is no longer there in PHP6. For example, following both are incorrect for PHP6:
<?php
$foo =& new StdClass();
?>
<?php
function &foo()
{
return new StdClass();
}
$f = foo();
?>
If we can't use something like this in PHP6:
$foo =& new StdClass();
What is the alternative to that, is there any way to mimic that?
EDIT:
Ans what about variables in PHP6, can we do that for variables eg:
$this->data =& $_SESSION;
You don't pass parameters by reference, but you still can/must declare your function/method as receiving parameters by reference.
i.e., you don't do this (passing parameters by reference) :
my_function(& $my_var);
function my_function($a) {
// ...
}
But you can do this (declaring the function as receiving parameters by reference) :
my_function($my_var);
function my_function(& $a) {
// ...
}
And... The code examples you gave are not related to call-time-pass-by-reference, but are related to return-by-reference.
For that second thing, what if you just remove the & ? The instance of the object that's been created inside the function will be returned, and you'll still be able to work with it, won't you ?
Objects are always passed by reference since PHP5, so this:
$foo =& new StdClass();
is the same as:
$foo = new StdClass();
.
Ans what about variables in PHP6, can we do that for variables eg:
$this->data =& $_SESSION;
I see no reason why not -- PHP will not be removing references, as they are far too useful. There is no other way to create a reference to a variable.
Call-time pass-by-reference has been deprecated for a while. It just means that instead of doing this:
function foo($a) { return ++$a; }
foo(&$my_a);
You would do this:
function foo(&$a) { return ++$a; }
foo($my_a);
This leads to a much cleaner and easier-to-understand programming style, and it also ensures that variables are always referenced when you expect, and not when you don't.
Dealing with objects is a special case -- they are always passed by reference, and the only way to simulate pass-by-value is to use clone:
$a = new StdClass();
$a->foo = 'bar';
$b = $a;
$a->foo = 'qux';
// $b->foo is 'qux' too
$a = new StdClass();
$a->foo = 'bar';
$b = clone $a;
$a->foo = 'qux';
// $a->foo is 'qux' but $b->foo is 'bar'
Hope that helps!
Related
I was looking at OOP Basics and saw a code like this (simplified it a bit)
You can see this class and the output
class Test{}
$a = new Test();
$b = new $a;
var_dump($b == $a); // true
What I don't understand is the $b = new $a but $a is already an object, so how/why does this work? If I do vardump $a the output is:
object(Test)#1 (0) {
}
So, how can that variable work with new keyword. I thought we could only use new with a class that is defined already, or with a string that points to a class ex:
$var = 'Test';
new $var; // ok
but in this case, $var is a string, not an another object.
It is a shortcut for creating new object. Before PHP 5.3.0 you have to do this:
$class = get_class($instance);
$newInstance = new $class;
As of PHP 5.3.0 you can do the same thing with this:
$newInstance = new $instance;
Very useful, in my opinion, because it eliminates the need for a temporary variable.
To clarify, this creates new object.
It is not cloning.
In other words, __construct() will be called instead of __clone().
I am a new in terms of PHP OOP programming, i don't understand when and how the following class names are and when shall i use them :
$a = new Classname();
$a = new Classname;
$a = ClassName::function();
$a = ClassName::getInstance();
Many thanks and sorry for silly question:
These are identical.
$a = new Classname();
$a = new Classname;
You can use them interchangeably when the class constructor does not take, or does not require other parameters.
Example:
class Classname
{
public function __construct($var = null)
{
// ..
}
static public function getInstance()
{
// ..
}
}
In this case you can use $a = new Classname; and $var will take the default value, or $a = new Classname('hello') and $var will be equal to the value passed.
These are both static method calls.
$a = ClassName::function();
$a = ClassName::getInstance();
One calls a method called "function" (which cannot exist - it is a reserved word), the other calls a method named "getInstance". When you use them really depends on what the methods do.
Static methods can be called without creating an object instance.
I.e.
Classname::staticMethod();
versus
$obj = new Classname;
$obj->method;
As for
$a = new Classname();
$a = new Classname;
No difference if __construct() has no arguments to receive.
As for
$a = ClassName::function();
$a = ClassName::getInstance();
this is just normal call of static methods
For:
$a = new Classname();
$a = new Classname;
These are just 2 different ways of saying the same thing: Create a new reference to class "Classname" without any parameters (php is more lenient in regards to if () and parameters must be given or not than many other programming languages).
For:
$a = ClassName::function();
$a = ClassName::getInstance();
These two are static calls of the functions "function()" and "getInstance()", thus $a would be set to the appropriate return value of these function. Static means that you can use the
functions without referening the class itself (thus $b=ClassName(); $a=$b->function() is not needed instead you can just write it as you did above).
$a = true;
1,new test($a);
2,new test(true);
Is there a difference between them(1,2), if have,what's of it? thank you,.
Well the other one uses a variable and the other one doesn't. This causes a fatal error in this case:
class test {
public function __construct( &$a )
{
}
}
$a = true;
new test($a);
new test(true); //Fatal error because this cannot be passed by reference
Strictly speaking, it depends on how test is defined.
If test is defined such that input parameters are passed by reference, then 2 would raise a fatal error, since true is a literal value.
Also, test could have side effects that mean that the order in which you execute lines 1 and 2 matter.
It depends on the constructor of the test class. In a regular pass-by-value constructor they are exactly the same:
class test {
public $b;
function __construct($a) { $this->b = $a; }
}
Here, $obj->b will be true for both your statements, as expected.
If, on the other hand, you are passing by reference you may get different results if you change the global $a later on. Example:
class test {
public $b;
function __construct( &$a ) { $this->b = &$a; }
}
$a = true;
$obj = new test($a);
$a = false;
$obj->b will be false in this case because it is a reference to $a! With references, you can also do it the other way around, changing $a from within the constructor:
class test {
function __construct( &$a ) { $a = false; }
}
$a = true;
$obj = new test($a);
$a will now be false even in the global scope!
In addition, new test(true) is not possible to do when passing by reference because you cannot have a reference to a literal value, only to other variables.
This is probably not the wisest question, but is it possible to return a variable from a function without redeclaring it?
function test(){
$a = 1;
return $a;
}
Would it somehow be possible to access $a with just calling the function? test();
not $a = test();
Is that the only way? I want to make $a available after calling the function.
You have to put the variable into the global scope:
http://codepad.org/PzKxWGbU
function test()
{
$GLOBALS['a'] = 'Hello World!';
}
test();
echo $a;
But it would be better to use a return value or references:
function test(&$ref)
{
$ref = 'Hello World!';
}
$var = '';
test($var);
I assume you want to change some context when you call the function.
This is possible. For example, all global variables share the same context across your application. If a function set's a global variable, its available in the global scope:
function change_global_variable($name, $value)
{
$GLOBALS[$name] = $value;
}
change_global_variable('a', 1);
echo $a;
However, whenever you do something like this, take care that you're destroying the modularity of your code. For example, if you have 50 functions like this and 80 variables, and then you need to change something, you need to change many, many places. And even harder, you don't remember which places you need to change and how they belong to each other.
It's normally better to make the context an object and pass it to the function that changes it, so it's more clear what the function does:
class Context extends ArrayObject {}
$context = new Context;
function change_context(Context $context, $name, $value)
{
$context[$name] = $value;
}
change_context($context, 'b', 2);
echo $context['b'], "\n";
This example demonstrates something that's called dependency injection. Instead of modifying the only one (global) context that exists in PHP, you are telling the function what it should modify, instead that it modifies hard-encoded global variables
There is a mix form of it, using the global variable scope to contain the context, so you spare to pass it as an additional parameter, however I only show it here for completeness, because it's not helping to retain modularity that well (however it's better than using more than one global variable):
class Context extends ArrayObject {}
$context = new Context;
function change_global_context($name, $value)
{
global $context;
$context[$name] = $value;
}
change_global_context('c', 3);
echo $context['c'], "\n";
Rule of thumb: Avoid global variables. Consider them of being very expensive and you don't want your code to be expensive.
No, it is not due to the scoping.
An option would be to declare $a before and then making it a global. It will then be available inside test:
$a = '';
function test(){
global $a;
$a = 1;
return $a;
}
echo $a; // 1
But may I ask why you want to do this? Are you just playing around or do you have a use case? You're most probably doing it wrong if you need this.
Maybe if you just want to show the variable you can use
function test(){
$a = 1;
echo $a;
return $a;
}
in this way if you want you can save the variable $a in a variable if not you can just show it calling the test function.
Hope it helps.
Nicola.
echo 'test';
class createdclass {
public $name;
}
class testc {
function &testm(){
$myvar =& new createdclass();
return $myvar;
}
}
$testo = new testc();
$a =& $testo->testm();
$a->name = 'Douglas';
$b =& $testo->testm();
$b->name = 'Scott';
echo $a->name;
echo $b->name;
myvar is a reference to an object
a and b are references to the same object
I changed a, then I changed b, but a wasn't changed by b
Why?
In your code each call to testm() creates a new instance of createdclass. So $a and $b aren't the same object.
Ok, first off, you shouldn't use $myvar =& new .... It's a deprecated syntax and is completely unnecessary (Since there's nothing to reference to)...
Secondly, you don't need the =& operator in the lines $a =& $testo->testm(). The fact that the method returns a reference is good enough. Not to mention that objects are passed by reference by default anyway, so you really don't need those lines anyway. I put them in the method signature function &foo() mainly for readability (to show that we're expecting the return to be a reference)...
Third, the problem is what you're referencing. References bind to a variable. When you leave the scope, since $myvar is a local variable (and as such is garbage collected -- it is deleted -- when the method exits), the bound reference disappears. So if you want that to work, you need to persist that variable.
Here's one example that works:
class testc {
protected $createdclass = null;
public function __construct() {
$this->createdclass = new CreatedClass();
}
public function &testm() {
return $this->createdclass;
}
}
$tester = new testc;
$a = $tester->testm();
$a->name = 'foo';
$b = $tester->testm();
echo $b->name; //displays "foo"...
in your example, a and b do not reference the same object because you create a new one in the testm() function.
here is a short example that might clarify things a little:
<?php
class createdclass {
public $name;
}
$a = new createdclass();
$a->name = 'Douglas';
// make $b reference the same as $a, i.e. let $p point to the same content as $a
$b = &$a;
$b = new createdclass();
$b->name = 'Scott';
echo $a->name;
echo $b->name;
?>
this will output ScottScott
if you want to learn more about references in php i'd recommend to read References Explained in the php manual