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