PHP Portal » Tutorials » Design Pattern mit PHP » Factory - die Fabrik die alles baut

Design Pattern mit PHP :: Factory - die Fabrik die alles baut

Design Pattern mit PHP :: Factory - die Fabrik die alles baut

Die Factory ist ein Hilfsmittel zur Erzeugung von Objekten. Sie wird verwendet, wenn erst zur Laufzeit des Programms bekannt ist, welche Klasse verwendet werden soll. Außerdem kann man es zur komfortablen Konfiguration einer Anwendung nutzen.
Ich verwende hier nicht das Factory Design Pattern im klassischen Sinne, sondern baue ein externe multifunktionale Klasse auf.

Eine einfaches Factory Design könnte so aussehen:

PHP Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Factory { /** * statische Methode zum bauen neuer Objekte * * @param string $class_name - Klassenname des gewünschten Objektes * @param array $params - Parameter für den Konstruktor der Klasse * @return object vom Typ $class_name **/ static public function get( $class_name, $params = null ) { require_once $class_name.'.class.php'; return new $class_name( $params ); } } // Benutzung des Factory Pattern $test = Factory::get( 'MeineKlasse' );

diese Art der Implementierung ist natürlich sehr fehleranfällig, darum wird es gleich um entsprechende Fehlerbehandlung erweitert

PHP Code
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
class Factory { /** * statische Methode zum bauen neuer Objekte, * inklusive Fehlerbehandlung * * @param string $class_name - Klassenname des gewünschten Objektes * @param array $params - Parameter für den Konstruktor der Klasse * @return object vom Typ $class_name **/ static public function get( $class_name, $params = null ) { // ist $class_name überhaupt gültig if( ! is_string( $class_name ) || ! trim( $class_name ) ) { throw new Exception( 'kein gültiger Klassenname' ); } // gibt es die Klasse überhaupt if( ! file_exists( $class_name.'.class.php' ) ) { throw new Exception( 'Datei nicht gefunden' ); } require_once $class_name.'.class.php'; // Objekt bauen try{ $obj = new $class_name( $params ); }catch( Exception $e ) { // ein Fehler innerhalb der anderen Klasse, // wir hängen die andere Meldung mit an throw new Exception( 'Fehler beim Konstruieren des Objektes: '.$e->getMessage() ); } // fertiges Objekt zurückgeben return $obj; } } // Benutzung des Factory Pattern try { $test = Factory::get( 'MeineKlasse' ); }catch( Exception $e ) { echo $e->getMessage(); }

Da man die Factory Klasse wiederverwenden möchte, muss sie etwas variabler werden. In diesem Beispiel definiere ich dafür einen Pfad, wo die einzubindenen Klassen zu finden sind. Außerdem werden die Klassen in Pakete zusammengefasst.

PHP Code
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
class Factory { /** * statische Methode zum bauen neuer Objekte, * inklusive Fehlerbehandlung * und variablen Klassenpfad sowie einer Paketverwaltung * * @param string $class_name - Paket::Klassenname des gewünschten Objektes * @param array $params - Parameter für den Konstruktor der Klasse * @return object vom Typ $class_name **/ static public get( $class_name, $params = null ) { // ist $class_name überhaupt gültig if( ! is_string( $class_name ) || ! trim( $class_name ) ) { throw new Exception( 'kein gültiger Klassenname' ); } // gibt es die Klasse überhaupt $file = _CLASS_PATH_.strtolower( str_replace( '::', DIRECTORY_SEPARATOR, $class_name ).'.class.php' ); if( ! file_exists( $file ) ) { throw new Exception( 'Datei nicht gefunden' ); } require_once $file; // Objekt bauen try{ // erstmal den Namen vom Paket trennen $tmp = explode( '::', $classname ); $name = array_pop( $tmp ); // Objekt bauen $obj = new $name( $params ); }catch( Exception $e ) { // ein Fehler innerhalb der anderen Klasse, // wir hängen die andere Meldung mit an throw new Exception( 'Fehler beim Konstruieren des Objektes: '.$e->getMessage() ); } // fertiges Objekt zurückgeben return $obj; } } // Benutzung des Factory Pattern // Pfad festlegen für die Klassen define( '_CLASS_PATH_', '/var/www/classes/' ); // Objekt bauen try { // bindet die Klasse "/var/www/class/meinpaket/meineklasse.class.php" ein $test1 = Factory::get( 'MeinPaket::MeineKlasse' ); // bindet die Klasse "/var/www/class/meinpaket/unterpakte/meineklasse2.class.php" ein $test2 = Factory::get( 'MeinPaket::UnterPaket::MeineKlasse2' ); }catch( Exception $e ) { echo $e->getMessage(); }

Damit ist eine Klasse geschaffen, welche einige schöne Bedingungen erfüllt:

  • Autoloader für unsere Klassen
  • Instanziieren aller benötigten Objekte
  • ordentliche Fehlerbehandlung

weiter »»