Equel Technologies

                                                                    Developing The Future

Factory Pattern in PHP

April 1st, 2009. Published under PHP. No Comments.

Factroy Pattern in PHP

Factory pattern, allows you to create a centric place in your classes where you could craete a new instance that depends on one or more classes.
In this example we’ll take a look at a parser in PHP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
<?php

interface IParser {
    public function getParams();
    public function setParams();
    public function parse();
    public function returnResults();
}

class XML_Parser implements IParser {
    public function getParams() {
   
    }
   
    public function setParams() {
   
    }
   
    public function parse() {
   
    }
   
    public function returnResults() {
        // Return the XML parser results
    }
}

class CSV_Parser implements IParser {
    public function getParams() {

    }

    public function setParams() {

    }

    public function parse() {

    }

    public function returnResults() {
        // Return the CSV parser results
    }
}

class XLS_Parser implements IParser {
    public function getParams() {

    }

    public function setParams() {

    }

    public function parse() {

    }

    public function returnResults() {
        // Return the XLS parser results
    }
}
?>

Now, how would you create a parser based on the file type that comes from the client through POST let’s say?
Of course you could do it like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php

$type = $_POST['parser_type'];

switch(strtoupper($type)) {
    case 'XML':
        $parser = new XML_Parser;
        break;
    case 'CSV':
        $parser = new CSV_Parser;
        break;
    case 'XLS':
        $parser = new XLS_Parser;
        break;
    default:
        $parser = NULL;
}

if ($parser == NULL)
    die('No such format');

?>

Well this code just check the type of parser and create an object of appropriate one, if type is other then the existing, the parser is set to NULL and the script stops.
The above code is ok, but you have to remember all class names XML_Parser, CSV_Parser and XLS_Parser.
What if each of these parser’s class constructor has parameters, and all of them are different?
You have to remember them too. Let’s see where the Factory Pattern can help us.

To make the above code more generic, we have to make a centric point in our code, where we could create an instance of the above classes without specifying the class names.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php

class Parser {
    const XML = 1;
    const CSV = 2;
    const XLS = 3;
   
    public static function getParser($type = self::XML) {
        switch($type) {
            case self::XML:
                return new XML_Parser;
                break;
            case self::CSV:
                return new CSV_Parser;
                break;
            case self::XLS:
                return new XLS_Parser;
                break;
            default:
                return NULL;
        }
    }
}

?>

Now you could use it like this:

1
2
3
4
5
6
7
<?php

$xml_parser = Parser::getParser();
$csv_parser = Parser::getParser(Parser::CSV);
$xls_parser = Parser::getParser(Parser::XLS);

?>

So here we use just one Class name Parser and send the type as the constant again from the same Class. The XML type is the default parser in case we dont specify any type.
We could move furthere and combine the Factory Pattern with the Singleton Pattern

Let’s rewrite a bit the Parser Class:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<?php

class Parser {
    const XML = 1;
    const CSV = 2;
    const XLS = 3;
   
    private static $parserInstance = NULL;
   
    public static function getParser($type = self::XML) {      
        switch($type) {
            case self::XML:
                return self::$parserInstance ? (self::$parserInstance instanceof XML_Parser) : new XML_Parser;
                break;
            case self::CSV:
                return self::$parserInstance ? (self::$parserInstance instanceof CSV_Parser) : new CSV_Parser;
                break;
            case self::XLS:
                return self::$parserInstance ? (self::$parserInstance instanceof XLS_Parser) : new XLS_Parser;
                break;
        }
    }
}

?>

Here we get just one instance of the specified type.
Now we create 4 objects:

1
2
3
4
5
6
7
8
<?php

$xml_parser = Parser::getParser();
$csv_parser = Parser::getParser(Parser::CSV);
$xls_parser = Parser::getParser(Parser::XLS);
$xml_parser2 = Parser::getParser(Parser::XML);

?>

We created one parser object for each type, but take a look at the last one, here the script will not create a second XML_Parser object, but will use the existing one. So after execution the $xml_parser and $xml_parser2 variables will point to the same object.

That’s it.

Happy PHPing!

Leave a Comment

You must be logged in to post a comment.