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().
Related
I know accessing object's properties dynamically using string e.g.
$obj->{$string};
But what about objects themselves?
Like I have string
$obj = '$model->property';
How to use this?
For example in if statement, to have something like
if($model->property) but by using this string?
Tried if({$obj}), if(${$obj})... nothing works.
I don't know if it even possible, but maybe?
I've set up a small test case...
class A {
public $b = 5;
}
$test = new A();
$var = "test";
echo ${$var}->b;
I think this last line is what your after.
Update:
If you want the object and the property, then the nearest I could get is to use...
class A {
public $b = 5;
}
$test = new A();
$var = "test->b";
list($var, $property) = explode("->", $var);
echo ${$var}->$property;
I hit a strange problem today and even as a PHP engineer i'm stumped at this:
It seems you can access a class constant from an object instance such as:
class a {
const abc = 1;
}
$a = new a();
var_dump($a->abc);
This will output null instead of the expected 1. I was able to do the following:
class a {
const abc = 1;
}
$a = new a();
var_dump(a::abc);
But in the context of a sub object that doesn't really know who the parent is exactly, i find it extremely annoying to do:
class a {
const abc = 1;
}
$a = new a();
$c = get_class($a);
var_dump($c::abc);
Is it me or this is completly stupid, if not, please enlighten me why its working that way.
EDIT
Another way of doing it but it's not really better:
class a {
const abc = 1;
}
class b {
public function getA(){
return new a();
}
}
$b = new b();
$c = $b->getA();
var_dump($c::abc);
This last example works more like what i am doing and experiencing...
Just use the instance variable with the scope resolution operator:
$a = new a();
var_dump($a::abc);
This prints 1.
I found a relatively nice and clean way to make my problem easier to live with. Here is the solution i've applied. It is not necessarely the best but for my uses it does exactly what i need.
By creating a magic __get method, i intercept the request for the constant name from and instance point of view and i use a quick reflection to see if that constant exists and return it's value.
This allows me to actually use all in one line a pattern that looks like this:
class a {
const abc = 1;
public function __get($key){
$r = new ReflectionObject($this);
if($r->hasConstant($key)){ return $r->getConstant($key); }
}
}
class b {
public function getA(){
return new a();
}
}
$b = new b();
var_dump($b->getA()->abc);
var_dump($b->getA()->def);
Althought i'd have liked to do:
var_dump($b->getA()::abc);
var_dump($b->getA()::def);
I guess this could be possible later in 5.4+ considering we finaly have array dereferencing, we could probably ask them to add static dereferencing soon.
The PHP documentation indicates that class constants are accessed via SRO (::) rather than ->.
<?php
class MyClass
{
const constant = 'constant value';
function showConstant() {
echo self::constant . "\n";
}
}
echo MyClass::constant . "\n";
ike I mentioned, in php constants are tied to the class definition, they are static by definition and cannot be accessed using the -> operator.
If you really want to use it with your coding paradigm, you can try the reflection class in php5.
class MyClass
{
const A = "I am A";
}
$o = new ReflectionClass( "MyClass" );
echo $o->getconstant("A"); //will print "I am A"
Also, I think the example in your EDIT might not work..I did not run it, but I am not sure if the SRO(::) can be invoked on anything that is not a class reference..
I know this is an old thread, but for people who want to know the best way to do this have a look at the PHP function constant().
With constant() you can simply do this:
$a = new a();
$value = constant(get_class($a)."::abc");
// $value === 1
this has been available since PHP 4, and still works perfectly in PHP 5.5
When trying to use const defined in a class inside a different namespace, the Scope Resolution Operator (::) can be used without problems as stated by the docs prefixing the namespace before the class in which the const was declared with this format:
(<namespace>"\")*<className>::<const>
With the next namespace, class and const definitions:
models/OperationModel.php
<?php
namespace models;
class OperationModel {
const OPERATION_INITIALIZING = 1;
}
You can use the const from another namespace\class like this:
controllers/MobileController.php
<?php
namespace controllers;
use models\OpertionModel;
class MobileController {
private function thingy() {
$operation_status = models\OperationModel::OPERATION_INITIALIZING;
}
}
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).
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
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!