When using nested objects (ObjTwo as a property of objOne):
$objOne->property = new ObjTwo($objOne);
What’s the best way to communicate? Here are a few methods I can think of:
Using specific get/set methods
class ObjTwo {
__construct($objOne){
$prop1 = $objOne->get_prop1();
// do something with prop1
$prop2 = $objOne->get_prop2();
// do something with prop2
// ... Having to write all these out is kind of a pain
// if you're going to have 20+ vars, and there's no
// easy way to loop through them.
}
}
The problem: Writing these out line by line, and having to update it when I add new properties.
I know that having a get/set method for each property is recommended, however I’d really like to loop through the data…
How about get_object_vars()
class ObjTwo {
__construct($objOne){
extract(get_object_vars($objOne));
// do something with the vars
}
}
The problem: This method bypasses the ability to use getter/setter methods, and each property would have to be public to be accessible.
Dynamic getter/setter method calls
Another way I have considered is to create an array of fields, and have a strict policy of naming the getter/setter methods:
class ObjTwo {
__construct($objOne){
$prop_array = array('prop1', 'prop2', 'prop_three');
$values = array();
foreach ($prop_array as $prop){
$values[$prop] = $objOne->get_{$prop}();
}
}
}
The problem: Every time I add a new property, I have to make sure to name the get_method() correctly, and update the $prop_array.
Anyone have any better solutions? Maybe just building an array of data?:
$objOne->property = new ObjTwo($objOne->get_data());
I like this solution
Having thought this through, here’s a little clarification: I’m not trying to just make identical copies from parent to child or vice-versa – I edited the above examples to show that a little better. It’s more just the idea of passing a subset of the object’s data from one place to another.
Instead of having to write:
$first_name = $this->member->get_first_name();
$last_name = $this->member->get_last_name();
$email = $this->member->get_email();
$display_name = $this->member->get_display_name();
// etc... and
$this->member->set_first_name($first_name);
$this->member->set_last_name($last_name);
$this->member->set_email($email);
$this->member->set_display_name($display_name);
// etc..
How about having a $this->member->get_fields('first_name', 'last_name', 'email', 'display_name'); method? I don’t like having to remember the field names exactly (fname, f_name, first_name, etc), so you could use class constants:
$data = $this->member->get_fields(array(
Member::FIRST_NAME, Member::LAST_NAME, Member::EMAIL, Member::DISPLAY_NAME
));
This way, I can loop through the returned data.
foreach ($data as $key=>$value) // ...
And setting the fields…
$this->member->set_fields(array(
Member::FIRST_NAME => $first_name, // THE BIG ADVANTAGE HERE:
Member::LAST_NAME => $last_name, // These field keys auto-complete
Member::EMAIL => $email, // so you don't have to remember them!
Member::DISPLAY_NAME => $display_name,
// etc...
));
Still thinking this through… any thoughts?
I think you’re asking the wrong question. Furthermore I think it would only be possible to really help, if you provided a real example instead of those pseudo examples. Every real situation is different with regard to the proper solution.
Generally all your proposals smell. It seems that what you need is not injection but inheritance. If your ‘child’ class really needs access to all or most of the properties of another class, it seems it should extend that class.
The parts of your software should know as little as possible about each other. In your comment you mention that you have a Member class and a Form class. I don’t know why any of them should know anything about the other at all.
Furthermore you seem to be under the impression that you need to map every property to a property in the new class. Why? If you pass an instance of a class into another class via custructor (= dependency injection) then you can map that instance to a property and then access all properties of the injected instance via that instance. No mapping needed.