Building a "factory" in PHP
I have created a File class, which takes care of all operations on files, I/O, and which acts differently depending on the nature of the files. I'm not happy with its actual structure, which looks like this:
class File
{
function __construct($id)
{
$bbnq = sprintf("
SELECT *
FROM documents
WHERE id = %u",
$id);
$req = bbnf_query($bbnq);
$bbn = $req->fetch();
$this->file_type = $bbn['file_type'];
$this->file_name = $bbn['file_name'];
开发者_如何学Go $this->title = $bbn['title'];
}
function display()
{
return '<a href="'.$this->file_name.'">'.$this->title.'</a>';
}
}
class Image extends File
{
function __construct($id)
{
global $bbng_imagick;
if ( $bbng_imagick )
$this->imagick = true;
parent::__construct($id);
}
function display()
{
return '<img src="'.$this->file_name.'" alt="'.$this->title.'" />';
}
}
Here I need first to know the file type in order to determine which class/subclass to use.
And I'd like to achieve the opposite, i.e. send an ID to my class, which returns an object corresponding to the file type. I have recently updated to PHP 5.3, and I know there are some new features which could be of use for creating a "factory" (late static bindings?). My OOP knowledge is pretty light, so I wonder if some have structural suggestions in order to make a unique class which will call the right constructor.Thanks!
I don't think late static bindings is relevant here - a factory pattern doesn't require them. Try this:
class FileFactory
{
protected static function determineFileType($id)
{
// Replace these with your real file logic
$isImage = ($id>0 && $id%2);
$isFile = ($id>0 && !($id%2));
if ($isImage) return "Image";
elseif ($isFile) return "File";
throw new Exception("Unknown file type for #$id");
}
public static function getFile($id) {
$class = self::determineFileType($id);
return new $class($id);
}
}
// Examples usage(s)
for ($i=3; $i>=0; $i--) {
print_r(FileFactory::getFile($i));
}
As an aside, you should definitely escape your output from the DB, no matter how safe you think it is. Test with double quotes in a title, for example (let alone more malicious input).
Also if it's part of a project, you might want to separate the View layer (your HTML output) from this Model layer, ie implement MVC...
In your factory's constructor, you need to determine the file type, then with that, create an object of the corresponding class. Something like this perhaps:
class File
{
public static function factory($id)
{
$fileData = <query this $id>
switch ($fileData->type) {
case image:
return new ImageFile($fileData);
break;
case html:
return new HtmlFile($fileData);
break;
default:
// error?
}
}
}
abstract class FileAbstract
{
// common file methods here
}
// override the custom bits for each type
class ImageFile extends FileAbstract
{
public function display()
{
// ...
}
}
class HtmlFile extends FileAbstract
{
public function display()
{
// ...
}
}
Your code would then simply be:
$myFile = File::factory($id);
$myFile->display();
精彩评论