PHP Design Patterns: Das Registry Pattern

Rainer Schulz » 02. Januar 2012 um 14:53 Uhr

6 Kommentare

PHP 

Vorwort

Ich beschäftige mich schon seit einiger Zeit mit Design Patterns im Softwaredesign, vor allem mit der Umsetzung in PHP. Aus diesem Grund möchte ich euch heute das Registry Pattern beziehungsweise meine Registryklasse vorstellen.

Wozu eine Registryklasse?

Da meine Projekte, in der Regel, alle objektorientiert geschrieben sind, habe ich mir überlegt, wie ich eine Globalisierung von Variablen, Konstanten und Funktionen erreichen kann.

Die Registryklasse

In einem meiner Bücher, über Design Patterns, bin ich dann über ein Intermezzo mit genau diesem Thema gestoßen. Dieses Intermezzo hat mich dazu bewegt mir eine Registryklasse zu schreiben, welche dann nur noch in den anderen Klassen bekannt gemacht werden muss (beziehungsweise das Objekt der Klasse).

Eine kleine Info am Rande

Meine Registryklasse benutzt das Singleton Pattern welches nur eine einmalige Instanzierung der Klasse erlaubt.

Registryklasse:
/**
 * Registerklasse.
 *
 * @author Rainer Schulz <‑‑‑‑‑‑@‑‑‑‑‑‑‑>
 * @link http://raischblog.de/
 * @copyright 2011 ‑ Rainer Schulz
 * @license CC BY‑NC‑SA 3.0 <http://creativecommons.org/licenses/by‑nc‑sa/3.0/>
 * @version 1.0 29/11/2011 18:41
 */
class RsRegistry
{
    // Klasseneigenschaften ====================================================

    private static $instance = null; // Speichert die Instanz der Klasse

    // Objekteigenschaften =====================================================

    /**
     * Array fuer die Variablen.
     * 
     * @access private
     */
    private $register = array();

    /**
     * Array zum Markieren von Konstanten.
     * 
     * @access private
     */
    private $readOnly = array();

    // Konstruktor und Destruktor ==============================================

    /**
     * Der Konstruktor.
     * 
     * @access private Instanzieren nur innerhalb dieser Klasse
     * @return object gibt ein neues Objekt der Klasse zurueck
     */
    private function __construct() {}

    /**
     * Der Destruktor.
     * 
     * @access public
     * @return void gibt nichts zurueck
     */
    public function __destruct() {}

    // Klassenmethoden =========================================================

    /**
     * Die getInstance‑Methode des Singleton‑Pattern.
     * Die Methode ist statisch (ohne Objekt aufrufbar).
     * Da der Konstruktor private ist, kann nur hier ein
     * Objekt der Klasse erstellt oder, wenn schon ein Objekt existiert,
     * geladen werden.
     * 
     * @access public
     * @return object gibt das Objekt der Klasse zurueck
     */
    public static function getInstance()
    {
        // wenn '$instance' noch auf 'null' steht
        if ( self::$instance === null ) {
            // wird einmalig ein Objekt dieser Klasse erzeugt
            self::$instance = new self();
        }

        // gibt das Objekt der Klasse zurueck
        return self::$instance;
    }

    // Objektmethoden ==========================================================

    /**
     * Methode zum setzen einer Konstanten.
     * 
     * @access public
     * @param string $key Name der Konstante
     * @param mixed $value Inhalt der Konstante
     * @return void gibt nichts zurueck
     */
    public function define( $key, $value )
    {
        if ( !$this‑>exists( $key ) ) {
            $this‑>register[$key] = $value;
            $this‑>readOnly[$key] = true;
            //return $this;
        } else {
            die(
                '<h1>Error: Constant \'<em>'.$key.'</em>\' is already created '.
                'in Registry!</h1>'
            );
        }
    }

    /**
     * 'Magische' Methode zum setzen einer Variable.
     * 
     * @access public
     * @param string $key Name der Variable
     * @param mixed $value Inhalt der Variable
     * @return void gibt nichts zurueck
     */
    public function __set( $key, $value )
    {
        if ( $this‑>isConstant( $key ) ) {
            die(
                '<h1>Error: Cannot override Constant \'<em>'.$key.
                '</em>\' in Registry!</h1>'
            );
        } else {
            $this‑>register[$key] = $value;
        }
    }

    /**
     * 'Magische' Methode zum holen einer Variable.
     * 
     * @access public
     * @param string $key Name der Variable
     * @return mixed gibt die Variable zurueck
     */
    public function __get( $key )
    {
        return $this‑>exists( $key ) ?
            $this‑>register[$key] :
            die(
                '<h1>Error: Key \'<em>'.$key.
                '</em>\' not found in Registry!</h1>'
            );
    }

    /**
     * 'Magische' Methode zum aufrufen einer Funktion.
     * 
     * Lambdafunktionen bzw anonyme Funktionen stehen ab PHP 5.3 zur Verfuegung.
     * 
     * @access public
     * @param string $key Name der Funktion
     * @param mixed $args Parameter der Funktion
     * @return function gibt die Funktion zurueck
     */
    public function __call( $key, $args )
    {
        if ( $this‑>exists( $key ) && is_callable( $this‑>register[$key] ) ) {
            return call_user_func_array( $this‑>register[$key], $args );
        }

        trigger_error( $key.' is not callable.', E_USER_ERROR );
    }

    /**
     * Methode entfernt eine gesetzte Variable.
     * 
     * @access public
     * @param string $key Name der zu entfernenden Variable
     * @return bool gibt einen Wahrheitswert zurueck
     */
    public function remove( $key )
    {
        if ( $this‑>isConstant( $key ) ) {
            die(
                '<h1>Error: Cannot remove Constant \'<em>'.$key.
                '</em>\' in Registry!</h1>'
            );
        } elseif ( $this‑>exists( $key ) ) {
            unset( $this‑>register[$key] );
            return true;
        }

        return false;
    }

    /**
     * Methode prueft, ob eine Variable/Konstante gesetzt ist.
     * 
     * @access public
     * @param string $key Name der zu pruefenden Variable/Konstante
     * @return bool gibt einen Wahrheitswert zurueck
     */
    public function exists( $key )
    {
        return array_key_exists( $key, $this‑>register );
    }

    /**
     * Methode prueft, ob $key eine Konstante ist.
     * 
     * @access public
     * @param string $key Name der zu pruefenden Variable/Konstante
     * @return bool gibt einen Wahrheitswert zurueck
     */
    public function isConstant( $key )
    {
        return array_key_exists( $key, $this‑>readOnly ) &&
               $this‑>readOnly[$key] === true ? true : false;
    }

    /**
     * Ueberschiebene Methode __clone() verhindert das Klonen des Objektes.
     * 
     * @access public
     */
    public function __clone()
    {
        trigger_error( 'Cloning of this object is not allowed.', E_USER_ERROR );
    }
}

Arbeiten mit der Registryklasse

Objekt erzeugen/holen

Ein Objekt der Klasse bekommt man nur über die getInstance()-Methode des Singleton Pattern.
$reg = RsRegistry::getInstance();

Variablen

Variablen speichern

Variablen können mit der magischen Methode __set(), wie folgt, gespeichert werden.
$reg‑>varName1 = 'String';
$reg‑>varName2 = 123;
$reg‑>varName3 = 1.23;
$reg‑>varName4 = array( 'eins' => 'one', 'zwei' => 'two' );
$reg‑>varName5 = $var;

Variablen holen

Variablen können mit der magischen Methode __get(), wie folgt, geholt werden.
$int = $reg‑>varName2;
echo $reg‑>varName1;
print_r( $reg‑>varName4 );

Variablen löschen

Variablen können mit der Methode remove(), wie folgt, gelöscht werden.
$reg‑>remove( 'varName3' );
$reg‑>remove( 'varName5' );

Konstanten

Konstanten speichern

Konstanten können mit der Methode define(), wie folgt, gespeichert werden.
$reg‑>define( 'BASE', 'http://raischblog.de' );
$reg‑>define( 'V2', 'http://v2.raischblog.de' );

Konstanten holen

Konstanten können mit der magischen Methode __get(), wie folgt, geholt werden.
$root = $reg‑>BASE;
echo $reg‑>V2;

Konstanten löschen

Konstanten können nicht gelöscht werden.

Funktionen

Funktionen speichern

Funktionen können mit der magischen Methode __set(), wie folgt, gespeichert werden.
$reg‑>getFullDateString = function ( $timestamp ) {
    return date( 'F d, Y ‑ H:i', $timestamp );
}

Funktionen holen

Funktionen können mit der magischen Methode __call(), wie folgt, aufgerufen werden.
echo $reg‑>getFullDateString( time() );

Funktionen löschen

Funktionen können mit der Methode remove(), wie folgt, gelöscht werden.
$reg‑>remove( 'getFullDateString' );

Abschließendes

Bei Anregungen oder Fragen zur Klasse benutzt, wie immer, einfach die Kommentarfunktion.

 

Diesen Beitrag teilen

Twitter Facebook Delicious Digg Bei allen Services (Mister Wong, Yigg, Infopirat etc.)

Ausnahmebehandlung mit PHP

Rainer Schulz » 01. Januar 2012 um 23:49 Uhr

0 Kommentare

PHP 

Vorwort

In den letzten Wochen habe wieder etwas mehr Zeit gefunden mich mit PHP zu beschäftigen. Daher werde ich in den nächsten Wochen ein paar von mir erstellte PHP-Klassen vorstellen. Welche das im Einzelnen sein werden, kann ich noch nicht sagen. In meinem heutigen Beitrag werde ich eine Exceptionhandlerklasse vorstellen.

Die Exceptionhandlerklasse

Die Exceptionhandlerklasse ist dafür gedacht, unbehandelte Exceptions (Ausnahmen) abzufangen und auszugeben. Bei Projekten, welche schon online sind, würde ich aber dazu raten, die Exceptions nicht auszugeben, sondern lieber in einer Datei zu loggen.

Exceptionhandlerklasse:
/**
 * Klasse zum abfangen von unbehandelten Exceptions.
 * 
 * @abstract
 * @author Rainer Schulz <‑‑‑‑‑‑@‑‑‑‑‑‑‑>
 * @link http://raischblog.de/
 * @copyright 2011 ‑ Rainer Schulz
 * @license CC BY‑NC‑SA 3.0 <http://creativecommons.org/licenses/by‑nc‑sa/3.0/>
 * @version 1.0 31/12/2011 18:06
 */
abstract class RsExceptionHandling
{
    private static $fullPath;

    public static function init( $trace = null, $fullPath = null )
    {
        self::$fullPath = $fullPath === false ? false : null;

        set_exception_handler( array(
            'RsExceptionHandling',
            $trace === true ? 'exceptionHandlerWithTrace' : 'exceptionHandler'
        ) );
    }

    public static function exceptionHandler( $e )
    {
        echo self::exceptionGetInfos( $e );
    }

    public static function exceptionHandlerWithTrace( $e )
    {
        echo self::exceptionGetInfos( $e );
        echo self::exceptionGetTrace( $e );
    }

    private static function exceptionGetInfos( $e )
    {
        $file  = self::$fullPath === false ?
                 basename( $e‑>getFile() ) :
                 $e‑>getFile();
        $class = get_class( $e );
        $nl    = "\r\n";

        return "<h1>Caught exception =&gt; $class</h1>$nl<p>Thrown in <strong".
               ">$file</strong> on line <strong>{$e‑>getLine()}</strong>.</p>".
               "$nl<p><strong>Message:</strong> {$e‑>getMessage()}<br /><stro".
               "ng>Code:</strong> {$e‑>getCode()}</p>";
    }

    private static function exceptionGetTrace( $e )
    {
        $traceArray = $e‑>getTrace();
        $nl         = "\r\n";
        $trace      = $nl;

        foreach ( $traceArray as $key => $content ) {
            $class    = '';
            $function = '';

            if ( !empty( $content['class'] ) ) {
                $class = " at class <strong>{$content['class']}</strong>";
            }

            if ( !empty( $content['function'] ) ) {
                $function = " in function <strong>{$content['function']}()".
                            '</strong>';
            }

            $file = self::$fullPath === false ?
                    basename( $content['file'] ) :
                    $content['file'];

            $trace .= "<p>#$key in <strong>$file</strong> on line <strong>".
                      $content['line']."</strong>$class$function</p>$nl";
        }

        return $trace;
    }
}

Initialisieren der Klasse

Die Klasse wird über die Methode init() initialisiert. Diese Methode kann man mit verschiedenen Parametern aufrufen.

Der parameterlose Aufruf der Methode bewirkt, dass nur die Datei, die Fehlermeldung und die Fehlernummer ausgegeben werden.
RsExceptionHandling::init();

Der Aufruf mit dem einzelnen Parameter true bewirkt, dass die Datei, die Fehlermeldung, die Fehlernummer und der komplette Pfad der Exception ausgegeben werden.
RsExceptionHandling::init( true );

Beim Aufruf der Methode mit false als zweiten Parameter bewirkt, dass keine kompletten Dateipfade, sondern nur der Dateiname ausgegeben wird.
RsExceptionHandling::init( true/null, false );

Abschließendes

Bei Anregungen oder Fragen zur Klasse benutzt einfach die Kommentarfunktion.

 

Diesen Beitrag teilen

Twitter Facebook Delicious Digg Bei allen Services (Mister Wong, Yigg, Infopirat etc.)

Alter eines Zeitstempels mit PHP ermitteln

Rainer Schulz » 04. Mai 2011 um 11:33 Uhr

9 Kommentare

PHP 

Vorwort

Ich schreibe schon einige Zeit das Backend für den Blog neu, dabei habe ich auch ein paar kleinere Funktionen geschrieben. Von diesen Funktionen möchte ich euch heute eine vorstellen von der ich denke, dass viele Webentwickler diese gebrauchen können.

Die PHP Funktion

Die folgende Funktion benötigt einen UNIX-Zeitstempel, welcher in der Vergangenheit liegt, als Übergabeparameter. Der übergebene Zeitstempel wird mit dem aktuellen Zeitstempel (time()) verglichen und das Alter berechnet. Ich benutze diese Funktion in der Version 2 dieses Blogs, zum Beispiel um zu zeigen, wie alt ein Artikel oder ein Kommentar ist.

Funktion zum Ermitteln des Alters eines Zeitstempels:
function getSince( $timestamp )
{
    if ( !is_numeric( $timestamp ) ) { return null; }

    $away = time() ‑ $timestamp;

    if ( $away < 60 ) {
        $since = $away.' Sekunde'.( ( $away == 1 ) ? '' : 'n' );
    } elseif ( $away < 3600 ) {
        $tsp = floor( $away / 60 );
        $since = $tsp.' Minute'.( ( $tsp == 1 ) ? '' : 'n' );
    } elseif( $away < 86400 ) {
        $tsp = floor( $away / 60 / 60 );
        $since = $tsp.' Stunde'.( ( $tsp == 1 ) ? '' : 'n' );
    } elseif( $away < 604800 ) {
        $tsp = floor( $away / 60 / 60 / 24 );
        $since = $tsp.' Tag'.( ( $tsp == 1 ) ? '' : 'en' );
    } elseif( $away < 2592000 ) {
        $tsp = floor( $away / 60 / 60 / 24 / 7 );
        $since = $tsp.' Woche'.( ( $tsp == 1 ) ? '' : 'n' );
    } elseif( $away < 31104000 ) {
        $tsp = floor( $away / 60 / 60 / 24 / 30 );
        $since = $tsp.' Monat'.( ( $tsp == 1 ) ? '' : 'en' );
    } elseif( $away < 155520000 ) {
        $tsp = floor( $away / 60 / 60 / 24 / 30 / 12 );
        $since = $tsp.' Jahr'.( ( $tsp == 1 ) ? '' : 'en' );
    } else {
        $since = 'Ewigkeiten';
    }

    return 'vor '.$since;
}

Abschließendes

Für wen diese Funktion noch nicht das Richtige ist, der kann auf PHP.net die Kommentare bei der time()-Funktion durchstöbern und schauen ob er dort fündig wird.

 

Diesen Beitrag teilen

Twitter Facebook Delicious Digg Bei allen Services (Mister Wong, Yigg, Infopirat etc.)

Optimierung des Blogs mit PHP

Rainer Schulz » 18. April 2011 um 15:33 Uhr

5 Kommentare

PHP 

Vorwort

Wie ich vor Kurzem berichtet habe, arbeite ich momentan an der zweiten Version dieses Blogs. Nicht nur das Design, sondern auch das komplette Backend des Blogs schreibe ich neu (in PHP). Im Zusammenhang damit habe ich mich ein wenig über Optimierungsmöglichkeiten informiert und möchte euch ein paar hier vorstellen.

Autoload von Klassen in PHP

Wenn man, so wie ich, in seinem Webprojekt alles in Klassen schreibt (objektorientierte Programmierung), dann hat man mehrere Möglichkeiten diese Klassen einzubinden. Früher habe ich zum Beispiel alle Klassen global via include oder request in meiner Konfigurationsdatei geladen. Man kann die Klassen aber auch immer nur an den Stellen laden an welchen man sie braucht, dass kann wiederum eine menge Schreibarbeit bedeuten.

Ab der PHP-Version 5 kann man dies nun bedeutend einfacher regeln. Die PHP-Version 5 bietet uns die Möglichkeit eine __autoload-Funktion zu definieren, welche automatisch aufgerufen wird sobald eine Klasse initialisiert werden soll (new Klassenname();).

Anmerkung: diese Funktion läd auch abgeleitete Klassen und implementierte Interfaces!

Nun habe ich, statt alle Klassen immer global zu laden, in meiner Konfigurationsdatei diese Funktion definiert:
function __autoload( $class ) {
    if ( !class_exists( $class ) && !interface_exists( $class ) ) {
        $paths = array(
            '/Pfad/zu/den/Klassen/class.'.$class.'.php',
            '/Pfad/zu/den/Interfaces/interface.'.$class.'.php',
            '/Pfad/zu/den/abstrakten/Klassen/abstract.'.$class.'.php'
        );

        foreach ( $paths as $file ) {
            if ( file_exists( $file ) && is_file( $file ) ) {
                require_once $file;
                return true;
            }
        }

        die( "<h1>Error: Class '<em>$class</em>' not found!</h1>" );
    }

    return true;
}

GZIP-Komprimierung mit PHP

Für Webmaster auf deren Servern die Module für die GZIP-Komprimierung (mod_deflate und mod_gzip bei Apache) nicht installiert oder aktiviert sind, bietet es sich an die in PHP eingebaute GZIP-Komprimierung zumindest für die PHP-Dateien zu verwenden. Damit lässt sich der Datentransfer von PHP-Dateien um bis zu 80% reduzieren.

Am Anfang einer PHP-Datei fügt man einfach folgenden Code hinzu:
if ( substr_count( $_SERVER['HTTP_ACCEPT_ENCODING'], 'gzip' ) ) {
    ob_start( 'ob_gzhandler' );
} else {
    ob_start();
}

Und am Ende einfach folgenden:
ob_end_flush();

Content Type und Charset via PHP-Header

Um das Rendern der Seite im Browser zu beschleunigen, kann man vorab via PHP einen Header übergeben. Dieser Header wird von den meisten Browsern ausgelesen, diese Browser brauchen dann nicht erst die Metadaten im HTML-Quelltext auslesen um das Rendern der Seite zu starten. Dieser Header sollte am Anfang der PHP-Datei gesetzt werden.

In meinem Blog benutze ich zum Beispiel diesen Header:
header( 'Content‑type: text/html; charset=ISO‑8859‑1' );

Abschließendes

Ich hoffe, dieser kleine Einblick war verständlich. Sollte ich noch weitere nützliche Optimierungen finden, werde ich diese hier wieder vorstellen.

 

Diesen Beitrag teilen

Twitter Facebook Delicious Digg Bei allen Services (Mister Wong, Yigg, Infopirat etc.)

Firefox 4 unter Ubuntu 10.10 installieren

Rainer Schulz » 11. April 2011 um 18:14 Uhr

5 Kommentare

Ubuntu und Firefox 

Installation bzw. Upgrade

Da ich einige Probleme hatte den Firefox 4 Download von Mozilla unter Ubuntu zu installieren, habe ich mich etwas informiert wie man es am besten anstellt. Und auf Ubuntuusers.de bin ich sehr schnell fündig geworden. Durch meine gescheiterten Versuche mit dem Download von Mozilla hatte ich erwartet, dass die Installation bzw. das Upgrade auf Firefox 4 ein steiniger Weg wird. Aber siehe da, am Ende war es dann doch sehr einfach.

Es reicht die Eingabe einer Zeile in das Komandozeilentool von Ubuntu (Terminal) welche mit Enter und der Eingabe des Benutzerpasswortes bestätigt wird:

sudo add‑apt‑repository ppa:mozillateam/firefox‑stable && sudo apt‑get update && sudo apt‑get upgrade

Nach dem Bestätigen läuft der Rest völlig automatisch im Terminal ab und man braucht nur zu warten, bis die Installation bzw. das Upgrade abgeschlossen ist.

Handelt es sich um ein Upgrade, wird beim ersten Start von Firefox 4 geprüft ob die vorhandenen Addons von Firefox mit der Version 4 kompatibel sind. Ist ein Addon nicht kompatibel wird es deaktiviert und ist in der Addonverwaltung ausgegraut. In den meisten Fällen existiert von diesen Addons bereits eine neuere Version die mit Firefox 4 kompatibel ist, dieses installiert man dann einfach und die alte Version des Addons verschwindet aus der Verwaltung.

Abschließendes

Ich hoffe dieses kleine Tutorial war verständlich und konnte euch bei der Installation von Firefox 4 helfen. Ich wünsche allen einen guten Start in die Woche.

 

Diesen Beitrag teilen

Twitter Facebook Delicious Digg Bei allen Services (Mister Wong, Yigg, Infopirat etc.)

12345