Unfortunately I cannot provide any code examples, however I will try and create an example.
My question is about Objects and memory allocation in PHP.
If I have an object, lets say:
$object = new Class();
Then I do something like
$object2 = $object;
What is this actualy doing? I know there is a clone function, but thats not what I'm asking about, I'm concerned about whether this is creating another identical object, or if its just assigning a reference to $object.
I strongly understand this to mean that it just creates a reference, but in some case usages of mine, I find that I get another $object created, and I can't understand why.
If you use the magic method __invoke, you can call an object similar to a function, and it will call that magic method.
class Object{
function __invoke(){ return "hi"; }
}
$object = new Object;
$object2 = $object();
echo $object2; // echos hi
That means that $object2 is equal to whatever that function returns.
Basically, you are calling a function, but using a variable as it's name. So:
function test(){ echo "hi"; }
$function_name = "test";
$function_name(); // echos hi.
In this case, you are just calling an object instead.
So, in reference to your question, this is actually not 'cloning' at all, unless the __invoke() function looks like this:
function __invoke(){ return this }
In which case, it would be a reference to the same class.
You are creating a second reference of the same object. Here is a proof:
<?php
class TestClass {
private $number;
function __construct($num) { $this->number = $num; }
function increment() { $this->number++; }
function __toString() { return (string) $this->number; }
}
$original = new TestClass(10);
echo "Testing =\n";
echo "--------------------------------\n";
echo '$equal = $original;' . "\n";
$equal = $original;
echo '$equal = ' . $equal . ";\n";
echo '$original->increment();' . "\n";
$original->increment();
echo '$equal = ' . $equal . ";\n";
echo "\n";
echo "Testing clone\n";
echo "--------------------------------\n";
echo '$clone = clone $original;' . "\n";
$clone = clone $original;
echo '$clone = ' . $clone . ";\n";
echo '$original->increment();' . "\n";
$original->increment();
echo '$clone = ' . $clone . ";\n";
Use clone if you want to create a copy of an instance.
Assuming that you mean
$object2 = $object;
And not
$object2 = $object();
PHP will create a reference to the original object, it will not copy it. See http://www.php.net/manual/en/language.oop5.basic.php, the section called
Object Assignment.
<?php
class Object{
public $value = 1;
public function inc(){
$this->value++;
}
}
$object = new Object;
$object2 = $object;
$object->inc();
echo $object2->value; // echos 2, proving it's by reference
Related
How can I create a property from a given argument inside a object's method?
class Foo{
public function createProperty($var_name, $val){
// here how can I create a property named "$var_name"
// that takes $val as value?
}
}
And I want to be able to access the property like:
$object = new Foo();
$object->createProperty('hello', 'Hiiiiiiiiiiiiiiii');
echo $object->hello;
Also is it possible that I could make the property public/protected/private ? I know that in this case it should be public, but I may want to add some magik methods to get protected properties and stuff :)
I think I found a solution:
protected $user_properties = array();
public function createProperty($var_name, $val){
$this->user_properties[$var_name] = $val;
}
public function __get($name){
if(isset($this->user_properties[$name])
return $this->user_properties[$name];
}
do you think it's a good idea?
There are two methods to doing it.
One, you can directly create property dynamically from outside the class:
class Foo{
}
$foo = new Foo();
$foo->hello = 'Something';
Or if you wish to create property through your createProperty method:
class Foo{
public function createProperty($name, $value){
$this->{$name} = $value;
}
}
$foo = new Foo();
$foo->createProperty('hello', 'something');
The following example is for those who do not want to declare an entire class.
$test = (object) [];
$prop = 'hello';
$test->{$prop} = 'Hiiiiiiiiiiiiiiii';
echo $test->hello; // prints Hiiiiiiiiiiiiiiii
Property overloading is very slow. If you can, try to avoid it. Also important is to implement the other two magic methods:
__isset();
__unset();
If you don't want to find some common mistakes later on when using these object "attributes"
Here are some examples:
http://www.php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading.members
EDITED after Alex comment:
You can check yourself the differences in time between both solutions (change $REPEAT_PLEASE)
<?php
$REPEAT_PLEASE=500000;
class a {}
$time = time();
$a = new a();
for($i=0;$i<$REPEAT_PLEASE;$i++)
{
$a->data = 'hi';
$a->data = 'bye'.$a->data;
}
echo '"NORMAL" TIME: '.(time()-$time)."\n";
class b
{
function __set($name,$value)
{
$this->d[$name] = $value;
}
function __get($name)
{
return $this->d[$name];
}
}
$time=time();
$a = new b();
for($i=0;$i<$REPEAT_PLEASE;$i++)
{
$a->data = 'hi';
//echo $a->data;
$a->data = 'bye'.$a->data;
}
echo "TIME OVERLOADING: ".(time()-$time)."\n";
Use the syntax: $object->{$property}
where $property is a string variable and
$object can be this if it is inside the class or any instance object
Live example: http://sandbox.onlinephpfunctions.com/code/108f0ca2bef5cf4af8225d6a6ff11dfd0741757f
class Test{
public function createProperty($propertyName, $propertyValue){
$this->{$propertyName} = $propertyValue;
}
}
$test = new Test();
$test->createProperty('property1', '50');
echo $test->property1;
Result: 50
I try to use a variable in each instance for a class.
My example class:
class test {
private static $gvalue;
function setValue($value)
{
$this->gvalue = $value;
}
function getValue()
{
return $this->gvalue;
}
}
Now I create to instances of this class "test" and print out some values.
$obj = new test();
$obj2 = new test();
echo "1: ";
echo $obj->getValue();
echo " / ";
echo $obj2->getValue();
$obj->setValue("green");
echo "<BR>2: ";
echo $obj->getValue();
echo "/";
echo $obj2->getValue();
My expectation was to get the following output:
1: /
2: green/green
But the result is:
1: /
2: green/
Did I understand something wrong? Or ist that not possible in PHP?
Goal at the end. I would like to set some variables/arrays during the creation of an instance (__construc) and us that for every instance during the code (per user request).
You have to change how you access the static property in your method implementation:
<?php
class Test {
private static $gvalue;
function setValue($value) {
self::$gvalue = $value;
}
function getValue() {
return self::$gvalue;
}
}
$obj1 = new Test();
$obj2 = new Test();
echo sprintf("1: %s/%s\n", $obj1->getValue(), $obj2->getValue());
$obj1->setValue("green");
echo sprintf("2: %s/%s\n", $obj1->getValue(), $obj2->getValue());
The output of that is:
1: /
2: green/green
You only set $gvalue for $obj:
$obj->setValue("green");
When you echo $obj2->getValue(); the value of $gvalue is still nothing, because you didn't set it for $obj2.
$obj and $obj2 are both different instances of the same class. They have the same characteristics etc. but they can hold different values. Thus the output that you got:
1: / 2: green/
is the correct output.
Is it possible to store a reference to an object's property (class member variable which holds a scalar data such as string or integer) within an object of a different class?
I am trying to have the following two echo statements produce identical results.
<?php
$x = new Type;
$x->name = 'abcd';
echo "x.name=" . $x->name . '<br/>';
echo "x.obj.name=" . $x->obj->value . '<br/>';
class Type
{
public $obj; //Instance of Property (Property class defined below)
public $name;
function __construct()
{
$this->obj = new Property($this->name);
}
}
class Property
{
public $value;
function __construct($v)
{
$this->value = $v;
}
}
$this->obj = new Property($this->name);
Is called at the time of object creation. Which is executed before the assignment.
i.e.
When you call $x = new Type;
The constructor is called and you try to copy 'name' which is empty by then
May be what you want it following, rather than passing the value, pass $this and keep the referance.
<?php
class Type
{
public $obj; //Instance of Property (Property class defined below)
public $name;
function __construct()
{
$this->obj = new Property($this);
}
}
class Property
{
public $value;
function __construct($ref)
{
$this->value = $ref;
}
}
$x = new Type;
$x->name = 'abcd';
echo "x.name=" . $x->name . '<br/>';
echo "x.obj.name=" . $x->obj->value->name . '<br/>';
You can pass the name value inside the constructor.
$x = new Type('abcd');
Without doing that, your constructor will not know what $this->name is yet. So we use it in the constructor and set the classes property before using it.
function __construct($p_name){
$this->name = $p_name;
$this->obj = new Property($this->name);
}
You could just as easily set the value after calling the constructor and then initialize the reference afterwards -
class Type {
public $obj;
public $name;
function setProperty(){
$this->obj = new Property($this->name);
}
}
$x = new Type;
$x->name = 'abcd';
$x->setProperty();
echo "x.name=" . $x->name;
echo "x.obj.name=" . $x->obj->value;
This is an old question but just to add to this.
You can have an object with methods and properties inside of another object..
Example
$obj1 = new class1();
$obj2 = new class2($obj1); // you just grabbed $obj1 and stuck it inside $obj2
Now you can use the stored object's methods like so:
$obj2->obj1->method_from_obj1();
or access the stored object's properties like so:
$obj2->obj1->property_of_obj1;
This is SUPER convenient if you instantiated an object of some API and want to use the API methods inside of your own object.
While at the time of answering this question is 9+ years old, I've encountered a similar issue today and found a way to do what's requested.
In short: you should use references. Here's a a working example (PHP 8):
<?php
class Source
{
public int $counter = 10;
}
class Consumer
{
public int $value = 0;
public function __construct(int &$value)
{
$this->value = &$value;
}
}
$source = new Source();
// Pass property of Source instance to the consumer.
$consumer = new Consumer($source->counter);
assert($consumer->value === 10);
// Changing value in the Source instance.
$source->counter = 15;
// ... and value in the consumer updated as well.
assert($consumer->value === 15);
exit;
So, the answer is yes, it is possible.
How is it possible to output methods in classes?
class Test {
function wee($param1, $param2){
return $param1.$param2;
}
}
I want to output the method wee and all its content.. I also need to know the names and how many parameters the method requires
Use ReflectionClass
$class = new ReflectionClass('Test');
$methods = $class->getMethods();
$parameters = $class->getMethod('wee')->getParameters();
var_dump($methods);
var_dump($parameters);
or a more stylized output
echo "<pre>";
$class = new ReflectionClass('Test');
$methods = $class->getMethods();
foreach($methods as $name){
echo $name;
}
echo "</pre>";
Does PHP have something similar to C++ member pointers? I want to use a member of a PHP object, whose name (the member's, not the object's) I only know at runtime. For example:
$object = new stdClass();
$object->NewMember = "value";
$member = 'NewMember';
// I don't know whether this is valid PHP,
// but you get what I'm trying to do.
echo $object->$member;
<?php
class Test
{
public $foo = 'bar';
}
$var = 'foo';
$test = new Test();
echo $test->$var;
Edit: after your update, yes, that will work.
You can use variables in member calls.
$methodName = 'some_method';
$myObj->$methodName($param);
Not sure if this will work for what you want.
In the following code I'm setting the $memberToGet at runtime:
class Person
{
public $foo = 'default-foo';
public $bar = 'default-bar';
}
$p = new Person();
$memberToGet = 'foo';
print "The Person's $memberToGet is [" . $p->$memberToGet . "]\n";
$memberToGet = 'bar';
print "The Person's $memberToGet is [" . $p->$memberToGet . "]\n";
No, PHP doesn't support (member) pointers. However you could use Reflection API.
class MyClass {
public function doSth($arg1, $arg2) { ... }
public static function doSthElse($arg1) { ... }
}
$ref = new ReflectionMethod('MyClass', 'doSth');
$ref->invokeArgs(new MyClass(), array('arg1', 'arg2'));
$ref = new ReflectionMethod('MyClass', 'doSthElse');
$ref->invokeArgs(null, array('arg1'));
As you can see in other answers you could also write:
class MyClass { ... }
$method = 'doSth';
$obj = new MyClass();
$obj->$method('arg1', 'arg2');
But I really don't recommend that way. It's tricky, obscure and much harder to debug and maintain.
By passing $this as a variable by reference, you can access members of that class.