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!

Daily WTF: boolean Werte im switch Konstrukt

5 Kommentare

Na, wer errät die Ausgabe von folgendem Code?

$var = true;

switch($var) {
    case "foobar":
        echo "foobar";
        break;

    default:
        echo "default";
}

Richtig – „foobar“! Vermutlich weil intern („foobar“ == true) gemacht wird und das true ist. ^^

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?

Older Entries