I've gotten myself into a situation in PHP where I need to access a class's constructor without knowing what the class is. I may be approaching this from the wrong design standpoint, so here is the situation - I am working in Drupal, writing a slight OO layer around their classless data-handling to allow some non-Drupal devs to join me on a project.
In Drupal, all content is considered a node. So, I made an abstract class - Node. Any content must have a specific content type. With OO, this is easy - I make a Person class that extends Node, or an Event class that extends Node, etc. Now comes the tricky part - part of my project allows these nodes to be "included" in other nodes. That is, if Node A includes Node B, then whenever A is displayed, the data from B is displayed. This means that whenever Node A is instantiated, it needs to instantiate Node B as well. BUT...Node is an abstract class. So, I can't instantiate a raw Node. I have to instantiate one of its implementing classes. So, as far as I can tell, I either need to write an abstract, static function that all extending classes must implement that returns the constructor...OR, I need to use reflection in some way to determine type, and somehow call the appropriate class constructor?
Without regard to Drupal, what is the most appropriate way to handle this issue from a PHP/OO programming standpoint?
Here is my code:
<?php
abstract class Node {
public $title, $short_summary, $full_summary, $body, $uri, $machine_type_name, $included_content;
public function __construct($node) {
##
## Set simple values
$this->title = $node->title;
$this->body = $node->body['und'][0]['safe_value'];
##
## Set clean uri if aliased
if (drupal_lookup_path('alias', 'node/'.$node->nid)) {
$this->uri = '/'.drupal_lookup_path('alias', 'node/'.$node->nid);
} else {
$this->uri = '/node/'.$node->nid;
}
##
## Set short summary if exists, else short form of body text
if(strlen($node->body['und'][0]['safe_summary'])) {
$this->short_summary = $node->body['und'][0]['safe_summary'];
} else {
$this->short_summary = text_summary($node->body['und'][0]['safe_value'], NULL, 100);
}
##
## Set full summary to concatenation of body
$this->full_summary = text_summary($node->body['und'][0]['safe_value'], NULL, 600);
##
## Add included content if module is enabled
if (module_exists('content_inclusion')) {
// is this possible? Is there a better design pattern available?
$this->included_content = Node::get_constructor(node_load($node->content_inclusion['und'][0]['value']));
}
}
public static abstract function get_all_published();
public static abstract function get_by_nid($nid);
public static abstract function get_constructor();
}
?>
static. I'm sure you'll become good friends.static, used for late static binding? (docs)