Building a “factory” in PHP

白昼怎懂夜的黑 提交于 2019-12-08 11:18:46

问题


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'];
            $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!


回答1:


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...




回答2:


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();


来源:https://stackoverflow.com/questions/4907018/building-a-factory-in-php

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!