I have an object in PHP, of the type MyObject.
$myObject instanceof MyObject
Now, in the class MyObject, there is a non-static function, and in there, I use the reference to "me", like $this, but I also have another object there.
Is it possible, without doing $this = $myObject, to achieve more or less the same effect, like something of the sort set_object_vars($this, get_object_vars($myObject))?
<?php
class MyObject
{
public function import(MyObject $object)
{
foreach (get_object_vars($object) as $key => $value) {
$this->$key = $value;
}
}
}
Will do what you want I guess, but you should be aware of the following:
get_object_vars will only find non-static properties
get_object_vars will only find accessible properties according to scope
The according to scope part is quite important and may deserve a little more explanation. Did you know that properties scope are class dependent rather than instance dependent in PHP?
It means that in the example above, if you had a private $bar property in MyObject, get_object_vars would see it, since you are in an instance of a MyObject class. This will obviously not work if you're trying to import instances of another class.
#Geoffrey Bachelet we can improve this:
class MyObject
{
//object or array as parameter
public function import($object)
{
$vars=is_object($object)?get_object_vars($object):$object;
if(!is_array($vars)) throw Exception('no props to import into the object!');
foreach ($vars as $key => $value) {
$this->$key = $value;
}
}
}
The difference is here that you can pass an ordinary array (hashtable) as well as an object. Think in example about some data coming from the database.
Related
I am trying to figure out what does bless do in perl - after reading their documentation - I am not very clear. Correct me if I am wrong, it allow to create properties in the class or object?
Someone coded this block of code
package Main::Call;
sub new
{
my ($class, $call) = #_;
my $self = $call;
bless($self, $class);
return $self;
}
So for example:
if (($statement = $db->prepare($sql)) && $statement->execute())
{
while (my $rt = $statement->fetchrow_hashref())
{
my $obj = Main::Call->new($rt);
push #reserv_call_objs, $obj;
}
return \#reserv_call_objs;
}
I am trying to convert this to PHP.
So I am assuming it would be like this?
class Call {
public function __construct($arr) {
foreach($arr as $key => $value)
{
$this->$value = '';
}
}
public function __set($key, $value) {
$this->$key = $value;
}
}
Perl has an unusual object model: An object is a reference that was “blessed” into a class. The bless just annotates the reference so that methods can be called upon the reference.
my $data = 1;
my $ref = \$data; # the reference can be of any type
$ref->foo; # this would die: Cannot call method "foo" on unblessed reference
bless $ref => 'Foo'; # *magic*
$ref->foo; # now this works
package Foo;
sub foo { print "This works\n" }
But usually references are only blessed inside the class'es constructor.
Perl does not dictate how an object should store its data. The most common method is to use a hash reference. This new is similar to your PHP __construct:
sub new {
my ($class, %init) = #_;
return bless \%init => $class;
}
which could be called like Foo->new(key => $value, ...).
What your Perl new does is rather unusual: It blesses the given argument into the appropriate class. This assumes that the $call is already a reference. If the $call was already blessed into some package, then it is re-blessed into this $class.
The most sane way to translate that to PHP is to stuff the $call into an instance's property, roughly like you did.
The bless function associates a class with a reference. That is, what ever you would pass to the new function would become an object of the Main::Call class, as long as it's a reference type. You can pass in a list reference, and it becomes an object. You can pass in a scalar reference, and it becomes an object.
There is no way to do exactly the same thing in PHP, but your attempt comes close to emulating the case when you pass a hash reference to new.
I am currently in the development of my Class in PHP.
I have an array with values in it, and I would like to use the array fieldname as a $this reference. Let me show you what I got:
<?php
class Server {
private $playlist;
private $mp3;
private static $ressourceFolder;
private static $sudoUser;
And in my array it contains:
array(6) {
["playlist"]=>
int(8002)
["mp3"]=>
int(1024)
["ressourceFolder"]=>
bool(true)
["sudoUser"]=>
bool(true)
}
So I would like to use in my foreach something to get the value of the array field into the class global variable, the array fieldname is the same as the variable so this 'should' work, but it doesn't :(
foreach($ressourceArray as $ressourceField=>$ressourceValue) {
$this->$ressourceField = $ressourceValue;
}
I would really appreciate if someone could tell me why this can't work and how to make this 'workable'...
Thanks in advance!
It does work, see Demo:
<?php
$array = array("playlist"=> 8002, "mp3"=>1024);
class Mix {
public function __construct($array) {
foreach($array as $key => $value) {
$this->$key = $value;
}
}
}
$class = new Mix($array);
var_dump($class);
It will assign new public members to the object $this based on key/value pairs of the array.
Dealing with bad named keys in the array
If the keys contain values that are not valid variable names, it can be non-trivial to access the properties later ({property-name}), see PHP curly brace syntax for member variable.
Casting the array to object before adding will help to prevent fatal errors for those key names that are completely invalid:
$object = (object) $array;
# iterate over object instead of array:
foreach($object as $key => $value) {
$this->$key = $value;
}
Those keys are just dropped by the cast.
You may get it working with the magic method __set and __get. See: http://php.net/manual/en/language.oop5.magic.php
And in my array it contains:
What array? That looks like a array dump of an instance of the class.
into the class global variable
What global class variable? Classes are not variables. Variables may hold references to objects, or class names.
Assuming you want to iterate through the properties of an object, and
$ressourceArray = new Server();
The code will work as expected.
If the loop is within a class method, then the loop should be....
foreach($this as $ressourceField=>$ressourceValue) {
$this->$ressourceField = $ressourceValue;
}
If you mean that you are trying to initialize the object properties from an array...
class Server {
...
function setValues($ressourceArray)
{
foreach($ressourceArray as $ressourceField=>$ressourceValue) {
$this->$ressourceField = $ressourceValue;
}
}
(BTW there's only one 's' in 'resource')
I am trying to build a base class that all of my classes extend from that allows for property access through simple $obj->property syntax, but if get_property() or set_property($value) is defined, then any attempt to get or set that property is routed through those getters and setters.
The tricky part, though, is that I would like updates to object properties to be reflected in an array (which is a property of the object, call it $changed_array) which can output an array of the properties that were changed, for some purpose, say, insertion into a db update call.
The problem lies in this sample:
class Sample {
private $changed_array;
public __get($var_ame){
if(method_exists($this, $method = 'get_' . $var_name)){
return $this->$method();
} else {
return $this->$var_name;
}
}
public __set($var_name, $value){
if(method_exists($this, $method = 'set_' . $var_name))}
return $this->$method($value);
} else {
// pseudo code
if($this->$var_name isset and isn't $value) { // add to $changed_array }
return $this->$var_name = $value;
}
}
}
Which works great, until there is a setter method defined like so:
public set_var_name($value){
// pretend we're mapping a db column to another name
$this->other_var_name = $value;
}
With this, the setter is called, but property it is setting is accessible, so the new value doesn't use the __set or __get function, and the changed array isn't updated with other_var_name as a changed property.
Is there some kind of hack, other that using something like $this->set('variable', 'value') to achieve the result? I would just write getter's and setters, but they vary based on the db schema, and it would be lovely if there was an elegantly simple solution.
Try this,
$objects = array("model", "make", "version");
foreach ($objects as $object) {
$getter = "get".ucfirst($object);
if (is_object($iProduct->$getter())) {
echo "getvalue"+$iProduct->$getter()
}
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...
New class is a subclass of the original object
It needs to be php4 compatible
You could have your classes instantiated empty and then loaded by any number of methods. One of these methods could accept an instance of the parent class as an argument, and then copy its data from there
class childClass extends parentClass
{
function childClass()
{
//do nothing
}
function loadFromParentObj( $parentObj )
{
$this->a = $parentObj->a;
$this->b = $parentObj->b;
$this->c = $parentObj->c;
}
};
$myParent = new parentClass();
$myChild = new childClass();
$myChild->loadFromParentObj( $myParent );
You can do it with some black magic, although I would seriously question why you have this requirement in the first place. It suggests that there is something severely wrong with your design.
Nonetheless:
function change_class($object, $new_class) {
preg_match('~^O:[0-9]+:"[^"]+":(.+)$~', serialize($object), $matches);
return unserialize(sprintf('O:%s:"%s":%s', strlen($new_class), $new_class, $matches[1]));
}
This is subject to the same limitations as serialize in general, which means that references to other objects or resources are lost.
A php object isn't a whole lot different to an array, and since all PHP 4 object variables are public, you can do some messy stuff like this:
function clone($object, $class)
{
$new = new $class();
foreach ($object as $key => $value)
{
$new->$key = $value;
}
return $new;
}
$mySubclassObject = clone($myObject, 'mySubclass');
Its not pretty, and its certianly not what I'd consider to be good practice, but it is reusable, and it is pretty neat.
The best method would be to create a clone method on the Subclass so that you could do:
$myvar = $subclass->clone($originalObject)
Alternatively it sounds like you could look into the decorator pattern php example
I would imagine you would have to invent some sort of a "copy constructor". Then you would just create a new subclass object whilst passing in the original object.