Wiederverwendbare Builder

Hinterlasse einen Kommentar

Ein Builder sollte normalerweise nur einmalig verwendet werden. Es kann aber Fälle geben, wo die Wiederverwendbarkeit ziemlich bequem ist. Hier ein Beispiel, wie es funktioniert.

<?php

class Builder {
        private $propA;
        public function withPropA($a) {
                $this->propA = $a;
                return $this;
        }
}

$builder1 = new Builder(); 
$builder1->withPropA("foo");

// this won't work as expected, since builder1 is modified before cloned
// $builder2 = clone $builder1->withPropA("bar");

// syntax error :(
// $builder2 = (clone $builder1)->withPropA("bar");

$builder2 = clone $builder1; 
$builder2->withPropA("bar");

print_r($builder1); // foo
print_r($builder2); // bar

Soweit das Beispiel, mit „einfachen“ (skalaren) Klassen Variablen (inkl. Arrays – diese werden ebenfalls kopiert). Wird jedoch ein inneres Objekt verwendet (oder ein „`&$pointer„`), muss man aufpassen. Folgendes Beispiel geht „schief“:

// als Fortsetzung zum oberen Code

class SubClass {
        public $propB;
}

$sub = new SubClass();
$sub->propB = "boo";

$builder1->withPropA($sub);
$builder3 = clone $builder1;
$sub->propB = "far"; 
// changes the state of both builder objects!!

print_r($builder1); // far!!
print_r($builder3); // far!!

Um solch einen Fall korrekt zu handhaben, kann man im Builder die „__clone“ Methode wie folgt implementieren:

class Builder2 {
        private $propA;
        public function withPropA($a){
                $this->propA = $a;
                return $this;
        }
        public function __clone() {
                if (is_object($this->propA)) {
                        $this->propA = clone $this->propA;
                }
        }
}

$builder1 = new Builder2();
$builder1->withPropA($sub);
$builder3 = clone $builder1;
$sub->propB = "yes"; 
// changes the state of $builder1 since this is the object set to builder1

print_r($builder1); // yes
print_r($builder3); // far (value before it was cloned)

Auch wenn hier jetzt das Klonen richtig funktioniert, ist der Code trotzdem etwas verwirrend, da $builder1 verändert wird, obwohl $sub erst nach dem clonen modifiziert wird. Daher sollte solcher Code aufgrund der Leserlichkeit trotzdem vermieden werden.

Trotzdem sollte das Klonen bei Objekt-Variablen auf jeden Fall wie im letzten Beispiel umgesetzt werden!

Advertisements

PHP Code Shit – when code really smells

4 Kommentare

Also ich hab ja lang nichts mehr geschrieben weil ich aktuell sehr wenig mit PHP zu tun hab bzw. nur im Zusammenhang mit unserer Software Lösung (evtl. starte ich einen allgemeinen Entwickler Blog oder so .. die Idee muss noch reifen).
Auf jeden Fall sollte ich gerade Fremd-Code analysieren und bin dabei auf ein paar heftige Code-Brocken getroffen, die ich euch nicht vorenthalten möchte. *gg*

#1

$year = date("Y");
$month = date("m");
$day = date("d");
$hour = date("H");
$minute = date("i");
$seconds = date("s");
$SQL = 'INSERT INTO '.$table.' VALUES ('.$id.','.$year.','.$month.','.$day.','.$hour.','.$minute.','.$seconds.')';

..wenn’s ganz schlecht läuft, wird die Sekunde aus der nächsten Minute sein oder sogar der Monat aus dem nächsten Jahr, dann ist Ende 2012 ganz kurz wieder 1. Januar 2012. :)

#2

//DEFINE NUMBERS
$numbers[] = "1";
$numbers[] = "2";
$numbers[] = "3";
$numbers[] = "4";
$numbers[] = "5";
$numbers[] = "6";
$numbers[] = "7";
$numbers[] = "8";
$numbers[] = "9";
$numbers[] = "0";

$n = 0;
while(isset($numbers[$n])){
    // use $numbers[$n]
    $n++;
}

^^

#3

//...
$page = $template->renderHtml();

$infoColumnPos = strpos($page, '<div id="infoColumn">');
$infoColumnEnd = strpos($page, '</div>', $infoColumnPos)+6;
$infoColumnLength = $infoColumnEnd - $infoColumnPos;
$page = substr_replace($page, "", $infoColumnPos, $infoColumnLength);

echo $page;

Äh … wofür sind nochmal Templates da?

Methodenaufrufe in PHP caseinsensitiv

4 Kommentare

Vor einigen Tagen entdeckt und immer noch von diesem „Feature“ verblüfft. :)
Ohne große Worte:

class FOO{
    function bar($msg){
        echo $msg;
    }
}

$f = new foo();
$f->Bar("lol"); //Ausgabe: lol

In PHP nur noch Exceptions statt Fehlermeldungen

4 Kommentare

Du hast keine Lust mehr auf die doofen Fehlermeldungen in PHP? Dann kannst du das mit set_error_handler erreichen. Davor bitte die Doku dazu lesen!

Hier mal ein Beispiel, wie sowas aussehen könnte:

set_error_handler('throwException', E_ALL);
function throwException($fehlercode, $fehlertext, $fehlerdatei, $fehlerzeile){
    throw new ErrorException($fehlertext, $fehlercode, 0, $fehlerdatei, $fehlerzeile);
}
trigger_error("foo-bar", E_ERROR);

Übrigens erzeugt „trigger_error“ den Fehler nicht weil „trigger_error“ aufgerufen wurde, sondern weil „trigger_error“ „E_ERROR“ als zweiten Parameter nicht akzeptiert. Ein echter E_ERROR also. :)
Leider ist es (noch) nicht möglich, für jeden Fehler Typen einen eigenen Handler zu definieren um zum Beispiel E_NOTICE Fehler anders zu behandeln als E_ERROR. Als zweiten Parameter akzeptiert set_error_handler (laut Doku) nur E_ALL oder E_STRICT. Könnte mir aber gut vorstellen, dass man das irgendwie austricksen kann.
Ich habe übrigens die ErrorException Klasse gewählt, da diese auch Dateiname und Zeile akzeptiert … wenn man diese Info schon mal hat, kann man diese ja auch gleich verwenden.
Als letzten Parameter kann man in der callback Funktion noch „$errcontext“ verwenden – der Inhalt ist bei einer Exception jedoch etwas fehl am Platz.

Nun wünsch ich allen die das wollen viel Spaß, denn damit wird das PHP Standard Fehler Handling ausgehebelt. Sowas wie z.B. „$resource = @fopen($irgendEineDatei);“ funktioniert dann nämlich nicht mehr bzw. ergibt eine schöne Exception falls ein Fehler auftritt. Das ist vor allem dann nervig, wenn man fremden Code einsetzt, der sich auf solche Konstrukte verlässt.

MVC Model geht auch ohne Datenbank!

14 Kommentare

Ich möchte mal ganz kurz etwas Frust über die implementierten MVC Pattern in den ganzen Frameworks loswerden, die ich in meinem kurzen Entwicklerleben verwendet habe:
Warum wird in der abstrakten Schicht der MVC Implementierung immer davon ausgegangen, dass hinter einem Model zwangsläufig eine Datenbank liegt. Ein Model ist doch nur die Abbildung irgendwelcher Daten die wo auch immer her kommen können, oder?! Zum Beispiel können Daten aus einem HTTP Request oder einer statischen Datei kommen, richtig?!

Also wenn dann sollte es einen Mapper geben, der aus der Datenbank die Models zaubert. Aber dass das Model seine eigenen Ursprung kennt finde ich äußerst nervig, denn wenn ich dann mal ein Datenbank unabhängiges Model schreibe, muss ich alle Methoden überschreiben, die irgendwas mit der Datenbank anstellen wollen.

So. Hab ich jetzt MVC falsch verstanden oder einfach nur noch nicht die richtigen Frameworks gefunden?

Idee: Fakten filtern

8 Kommentare

Da das Web immer größer und unüberschaubarer wird, wäre es doch an der Zeit eine Anwendung zu schreiben, mit der man einzelne Fakten zu ausgewählten Themen zusammenfassend sammeln könnte. Über solche Channels würde man also nur die Infos bekommen, für die man sich interessiert und dazu auch noch so extrem zusammengefasst, dass man schnell einen Überblick bekommt und dadurch mit Leichtigkeit viele Themen im Blick hat. Interessiert man sich für einen gewisse Information mehr, kann man sich die Quelle der Information genauer anschauen und erhält Links zu weiteren ähnlichen Quellen.
Ein Themenchannel wird über definierte Keywords gesteuert und bezieht seine Informationen automatisch aus allen möglichen Datenquellen: Twitter, Blogs, News, Delicious etc.
Also im Prinzip ist das sowas wie ein Feedreader, nur das die Informationen automatisch anhand von Keywords gesammelt werden und extrem kompakt und übersichtlich präsentiert werden.

Was haltet ihr von der Idee? Gibt es sowas viellecht schon?

Statischen Aufruf von Instanzaufruf unterscheiden … geht nicht

4 Kommentare

Gerade hatte ich die Idee mit „if(isset($this))“ zu unterscheiden, ob eine statische Method über die Klasse oder über ein Objekt aufgerufen wurde.
Beispiel:

class Foo {
    public static function bar() {
        if (isset($this)) {
            echo "i am an object. ";
        } else {
            echo "this is a static call. ";
        }
    }
}

// beispiel verwendung
Foo::bar();
$f = new Foo();
$f->bar();

Erwartet hatte ich, dass dabei „this is a static call. i am an object. “ rauskommt, das war aber nicht der Fall. In beiden Fällen wird „this is a static call. “ ausgegeben.
Das bedeutet also, dass eine statische Methode immer statisch aufgerufen wird, selbst wenn der Aufruf über ein Objekt stattfindet.

Older Entries