I have an object, KbArticle, that originally in it's constructor, would try to return null if the SQL query that retrieves the data for its required properties came up with 0 rows. A friend told me that constructors shouldn't return null, and that I should look into the Factory Pattern. I did and I see the benefits, so I'm wondering how I can implement this better/"properly."
Quick overview: Knowledgebase.php is the page an end-user sees, it calls a function in factory.php which calls the constructor in kb_fnc.php and then it ends up creating the object back on Knowledgebase.php if things all go well.
Knowledgebase.php
<?php
if ($kb = Factory::make('KbArticle', $_GET['a'])) {
$kb->echoNavTrail();
} else {
die('failed constructor');
}
?>
factory.php
Note: It disappoints me that apparently the functions in here have to be public instead of private, because my factory method is static? This seems not ideal, or am I incorrect?
<?php
require_once('kb/kb_fnc.php');
class Factory {
public static function make($obj, $params) {
$succ = false;
switch($obj) {
case('KbArticle'):
return tryNewKnowledgebaseArticle($params);
break;
}
}
}
function tryNewKnowledgebaseArticle($id) {
try {
$kb = new KbArticle($id);
} catch (Exception $e) {
return null;
}
return $kb;
}
?>
kb_fnc.php
Note: Is throwing an exception here smart? In my quick tests yesterday, I couldn't access the custom string on the exception after it was chained back, so it seems not that useful—at least not without knowing how to log that string to console at the end or something, for debugging purposes.
class KbArticle {
function __construct($id) {
//do SQL
if (odbc_num_rows($res) > 0) {
//fill in properties with data from table
} else {
throw new Exception('KbA constructor failed SQL query');
}
}
}
My biggest questions are regarding:
- Does this look sensible?
- Can I access that custom exception string in my
factoryclass, so I can ultimately encode it inJSONfor aconsole.logfor easier debugging if things go awry down the line? - The functions in my
factoryclass being public instead of encapsulated as private bothers me.
$e? \$\endgroup\$