php-resource




Archiv verlassen und diese Seite im Standarddesign anzeigen :
Best Practices OOP


 
ShopNix
23-04-2016, 19:44 
 
Nachdem ich mich nun schon eine ganze Weile mit PHP herumschlage und mich bisher einigermaßen erfolgreich um das Thema OOP gedrückt habe, möchte ich jetzt versuchen, den Einstieg zu schaffen.

Aktuell treiben mich zwei Fragen um:

1. Wie reiche ich ich ein Datenbankobjekt, dass ja nun an allen Ecken und Enden gebraucht wird, durch?

2. Ein SOAP-Service gibt mir ein recht komplexes Objekt als Response zurück. Jede Doku zu OOP zeigt mir, wie ich vom Allgemeinen zum Besonderen gehe. In dem Falle ist es umgekehrt. Jedes Response-Objekt hat ein paar Gemeinsamkeiten wie Success und Timestamp, aber auch Besonderheiten, die sowohl von den Inhalten, als auch vom Request abhängen. Wie fange ich an?

 
chorn
25-04-2016, 10:51 
 
zu 1. sieh dir mal MVC und Dependency Injection an

 
ShopNix
26-04-2016, 18:10 
 
Mit derlei Schlagworten kann ich nur wenig anfangen. Aber sei's drum. Ich habe mir eine OpenSource Software angeschaut und und daraus die folgende Klasse gebastelt:

class sxDb {

/** Database connection object
* @var DB */
protected static $DB = null;

/** sxDb Instance */
protected static $_instance = null;

/** Returns database object
* @return PDO */
public static function getDb()
{
if ( self::$DB === null ) {
$oInst = self::getInstance();

$aDbConf = array('dbHost' => 'localhost',
'dbUser' => 'xyz',
'dbPass' => 'zyx',
'dbName' => 'ebay',
'dbEngine' => 'mysql',
'dbCharset' => 'utf8');

$dns=$aDbConf['dbEngine'].':dbname='.$aDbConf['dbName'].';host='.$aDbConf['dbHost'].';charset='.$aDbConf['dbCharset'];
$oDb = new pdo($dns, $aDbConf['dbUser'], $aDbConf['dbPass']);
$oDb->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$oDb->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);

self::$DB = $oDb;
}
return self::$DB;
}

/** Returns Singleton instance
* @return sxDb */
public static function getInstance()
{
if ( !self::$_instance instanceof sxDb ) {
self::$_instance = new sxDb();
}
return self::$_instance;
}
}

Das scheint ein Singleton Design Pattern zu sein und funktioniert erstmal.

Nun kann ich an beliebiger Stelle im Programm

$db = sxDb::getDb();

notieren, und habe eine bestehende Verbindung, falls nicht, wird sie aufgebaut.

Kritik ist ausdrücklich erwünscht.

 
ShopNix
26-04-2016, 18:21 
 
Und gleich die nächste Frage.

$db = sxDb::getDb();
$sql = "insert into sxc_config (configuration_key, configuration_value, configuration_group_id) values (?, ?, ?)";
try {
$sth = $db->prepare($sql);
} catch (Exception $ex) {
die("$sql hat nicht funktioniert: ".print_r($ex)."\n ");
}

Oben habe ich die Attribute
$oDb->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

und erwartet, dass mit ein Fehler um die Ohren fliegt, wenn das SQL-Statement falsch ist, im obigen Beispiel ist der Name der Tabelle falsch.

Tatsächlich poppt der Fehler erst beim execute auf.

 
h3ll
26-04-2016, 19:20 
 
Tatsächlich poppt der Fehler erst beim execute auf.

Das liegt daran, wie PDO arbeitet. Erst beim Execute wird eine Abfrage an die Datenbank gesendet.

static ist übrigens böse und solltest du gleich raushauen. Außerdem hat die Datenbankkonfiguration nichts in einer Klasse verloren. Sowas gehört in Konfigurationsdateien (zB. ini-Dateien).

 
ShopNix
26-04-2016, 20:39 
 
Das liegt daran, wie PDO arbeitet. Erst beim Execute wird eine Abfrage an die Datenbank gesendet.

Danke. Das ist natürlich Bockmist, denn MySQL unterstützt das richtig.

mysql> prepare stmt1 from 'select Description from ShippingServiceDetail limit 10';
ERROR 1146 (42S02): Table 'ebay.ShippingServiceDetail' doesn't exist

mysql> prepare stmt1 from 'select Description from ShippingServiceDetails limit 10';
Query OK, 0 rows affected (0.00 sec)
Statement prepared


static ist übrigens böse und solltest du gleich raushauen.

Ich bin auch böse und lass mich trotzdem nicht hauen. Schon gar nicht raus.

Außerdem hat die Datenbankkonfiguration nichts in einer Klasse verloren. Sowas gehört in Konfigurationsdateien (zB. ini-Dateien).

Das ist ein Beispiel zu Lernzwecken.

 
h3ll
26-04-2016, 20:53 
 
Das ist ein Beispiel zu Lernzwecken.

Man lernt mehr, wenn mans gleich richtig macht.

 
hall
04-05-2016, 18:09 
 
Wie schon hier geschrieben wurde, kann man solche Abhängigkeiten beispielsweise mit "Dependency Injection" auflösen und die Anwendung auch leichter "testbar", etc machen:

https://de.wikipedia.org/wiki/Dependency_Injection

Dann wäre auch die angesprochene Auslagerung von Konfigurationsdaten besser handle und wartbarer als mit "hard" codierten Werten in irgendeiner Klasse (unflexibel, blöd wenn man was testen will, etc). Das so statisch auszulagern, naja, es kommt auf das Projekt, das Ziel, eigene Erfahrung an :D Aber damit schaffst du dir eine Abhängigkeit zu dieser Klasse.. Was ist, falls eine andere Datenbank benutzt werden soll.. oder eine mit "Dummy"-Werten zu präsentationszwecken..? Vielleicht ist es auch zuviel am Anfang, wenn man OOP verstehen möchte.

Um DI besser zu verstehen, sei auch hier, wie meist woanders, auf "pimpel" hingewiesen:

Pimple - A simple PHP Dependency Injection Container (http://pimple.sensiolabs.org/)

Zu Deiner zweiten Frage, fällt mir spontan nur WSDL ein - aber Soap ist nicht wirklich mein Thema :)

SOAP and PHP in 2014 — Whitewashing (http://www.whitewashing.de/2014/01/31/soap_and_php_in_2014.html)

https://de.wikipedia.org/wiki/Web_Services_Description_Language

schönen Feiertag zusammen

(von einem der schon ewig nicht mehr online war :D )

 
ShopNix
09-05-2016, 13:09 
 
...
Dann wäre auch die angesprochene Auslagerung von Konfigurationsdaten besser handle und wartbarer als mit "hard" codierten Werten in irgendeiner Klasse (unflexibel, blöd wenn man was testen will, etc). Das so statisch auszulagern, naja, es kommt auf das Projekt, das Ziel, eigene Erfahrung an :D Aber damit schaffst du dir eine Abhängigkeit zu dieser Klasse.. Was ist, falls eine andere Datenbank benutzt werden soll.. oder eine mit "Dummy"-Werten zu präsentationszwecken..? Vielleicht ist es auch zuviel am Anfang, wenn man OOP verstehen möchte. ...

Ich begreife beim besten Willen nicht, wie man sich an hart codierten Zugangsdaten der Datenbank in einem Beispiel abarbeiten kann. In einem Beispiel geht es darum, einen beschriebenen Zusammenhang zu verdeutlichen, idealerweise so, dass es direkt funktioniert und leicht lesbar ist.

Schön, vielleicht hätte ich besser mit der Konfiguration als mit der Datenbank begonnen. Beides sind Dinge, die man an allen Ecken und Enden in nahezu jedem Programm braucht, das eine Datenbank nutzt.

In meinem Fall ist's ohnehin fast egal, weil in der Geschichte, die ich hier vorhabe, alle weiteren Konfigurationsparameter in der Datenbank liegen werden. Wobei mir, um das noch einmal zu betonen, durchaus klar ist, dass die Zugangsdaten im Endprodukt absolut nichts in der DB-Klasse verloren haben.


Um DI besser zu verstehen, sei auch hier, wie meist woanders, auf "pimpel" hingewiesen:

Pimple - A simple PHP Dependency Injection Container (http://pimple.sensiolabs.org/)


Das scheint wirklich hilfreich zu sein, um die Idee zu verstehen, das schaue ich mir noch genauer an. Vielen Dank.


Zu Deiner zweiten Frage, fällt mir spontan nur WSDL ein - aber Soap ist nicht wirklich mein Thema :)

SOAP and PHP in 2014 — Whitewashing (http://www.whitewashing.de/2014/01/31/soap_and_php_in_2014.html)

https://de.wikipedia.org/wiki/Web_Services_Description_Language ...

Die Antwort ist grundsätzlich nicht falsch, geht aber an meiner Frage vorbei. ;)

Aus der WSDL, die in diesem Falle etwas über 5 MB groß ist, die Objektstruktur zu entwickeln, stelle ich mir schon sehr mühsam vor. Zumal wenn man, wie ich, gerade mal den Einstieg in die Welt der Objekte finden will.

Vermutlich wird mir nichts anderes übrig bleiben, als für die recht begrenzten Teilbereiche, die in der WSDL beschrieben sind, den Baum von oben nach unten durchzugehen und mich dann von den Wurzeln wieder hochzuarbeiten.


schönen Feiertag zusammen

(von einem der schon ewig nicht mehr online war :D )

Das Wochenende habe ich offline genossen. Danke.


Alle Zeitangaben in WEZ +2. Es ist jetzt 05:25 Uhr.