Reputation: 691
I'm working on a project that I'm migrating from procedural code to a class architecture, and I've run into something that I don't know how to address. Please see the following code:
// StackOverflow example code
# in file classes/parent_class.php
class Parent_class {
protected $aggregator_array = array();
const TARGET_DATA_LEVEL = 31; // Bit-mask for selecting appropriate aggregation level
public function __construct()
{
$this->child_class_1 = new child_class_1();
$this->child_class_2 = new child_class_2();
}
protected function aggregate_data($data_level, $message, $file, $function, $line)
{
$add2array = $data_level & self::TARGET_DATA_LEVEL;
if ($add2array > 0)
{
// code to create the array's index, based on current time and other factors
$this->aggregator_array[$index] = $message;
}
}
}
# in file classes/child_class_1.php
class child_class_1 extends Parent_class {
private function do_something()
{
// some code here
$data_level = 1; // simulate an error of some kind
$message = 'Foo!';
$this->aggregate_data($data_level, $message, __FILE__, __FUNCTION__, __LINE__);
}
}
# in file classes/child_class_1.php
class child_class_2 extends Parent_class {
private function do_something_else()
{
// some code here
$data_level = 2; // simulate nav message
$message = 'hello world!';
$this->aggregate_data($data_level, $message, __FILE__, __FUNCTION__, __LINE__);
}
}
As you can see, I have a parent class that contains a data aggregation method, and multiple child classes that are trying to access that same method to store messages for later retrieval at the end of the script's run. This is all well and good, except that the intent (collecting the aggregated messages into a central array) is not being actualized. All of the calls to aggregate_data are working well, but calls from any child class result in the storing of data into that child's own aggregator_array, which is not optimal. Sure, I can do an array_merge() to insert the child entries into the parent array, but if I have more than a couple of child classes (and I expect to have a half dozen or more), we're talking about a coding nightmare. I've tried using static properties, but that obviously won't work because I'm needing to dynamically alter the parent array.
So my question is, how can I alter a parent object's properties from a child class, without creating a child property of the same name?
Now I'm perfectly happy to use "non-related" classes (e.g. removing the "extends parent_class" from the current child classes), but the problem then shifts to how to access an unrelated class's properties and methods, which I haven't the foggiest clue of how to do, if it's even possible.
Upvotes: 0
Views: 326
Reputation: 1657
Are child_class_* objects really different kinds of Parent_class? Or do they just happen to interact with Parent_class in order to aggregate some stuff? Based on the method names do_something and do_something_else, they're really not responsible for that kind of logic. Unless you're overriding/defining a certain behavior of a specific kind of Parent_class, for example if you want the behavior of aggregate_data() to change polymorphically, you probably don't need to extend Parent_class.
That said, one way you could access the "unrelated" class's properties is to pass an instance of Parent_class into your do_* functions:
// in your main script
$aggregator = new Parent_class();
$thing1->do_something( $aggregator );
$thing2->do_something_else( $aggregator );
// in child_class_1, which you should rename ;-)
private function do_something( $aggregator )
{
...
$aggregator->aggregate_data( $data_level, $message, __FILE__, __FUNCTION__, __LINE__ );
}
// in child_class_2, ditto
private function do_something_else( $aggregator )
{
...
$aggregator->aggregate_data( $data_level, $message, __FILE__, __FUNCTION__, __LINE__ );
}
Alternatively, you could pass an instance of Parent_class into the constructor of your two "child" classes. That keeps the method signature of your do_* methods less cluttered. Then you could do something like:
// main script
$aggregator = new Parent_class();
$thing1 = new child_class_1( $aggregator );
$thing2 = new child_class_2( $aggregator );
// within each of the do_* methods:
$this->$aggregator->aggregate_data( $data_level, $message, __FILE__, __FUNCTION__, __LINE__ );
For this approach, make sure you also add a constructor that sets $this->aggregator in the "child" classes.
Later on in the code, you can access the "central array" by calling $aggregator->GetAggregatorArray
or whatever.
Also, you are not initializing $index
, but you don't need that variable anyway (assuming $aggregator_array
is a numerical array). You can just do:
$this->aggregator_array[] = $message;
Upvotes: 1