php.de

Zurück   php.de > php.de Intern > Wiki Diskussionsforum > Tutorials

Tutorials Hier findest Du Tutorials, welche nach und nach ein fertiges Script ergeben. Sehen, lernen & verstehen!

Antwort
 
LinkBack Themen-Optionen Thema bewerten
Alt 15.02.2008, 17:48  
moderatives Dielektrikum
 
Benutzerbild von nikosch
 
Registriert seit: 21.05.2008
Beiträge: 34.248
PHP-Kenntnisse:
Fortgeschritten
nikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz sein
Standard [Erledigt] PHP: 'Templating' auf Basis von sprintf ()

Nachfolgend möchte ich eine Funktion vorstellen, die ich gestern geschrieben habe. Ich denke, dem ein oder anderen könnte die einmal hilfreich sein.

Eigentlich bin ich ein Fan der printf () Funktionen [1], über die man in einen gegebenen Formatstring eine zugeordnete Liste von Parametern einfügen lassen kann.
Für bestimmte Anwendungen waren mir diese Funktionen aber nicht flexibel genug.

Ausgangssituation

Als Beispiel nehmen wir eine Methode eines Fehlerobjektes, die beliebige Fehlerdaten über einen variablen Formatstring in ein Logfile schreiben soll.
Dazu werden die Objektmember via sprintf () in den Formatstring eingetragen. Um eine beliebige Reihenfolge der Daten zu ermöglichen, bieten printf () & Co das sogenannte Argument swapping an, bei dem der gewünschte Paramter über einen Index n$ angegeben wird.


PHP-Code:
<?
class MyError
  
{
  static 
$sFormat  '%6$s %2$s (error %1$d) in %4$s line %5$d'// Logline format, swapped arguments
  
static $sLogfile 'path/to/logfile';
  
  public function 
__construct ($iType $sMessage $aBackTrace $sFile $sLine)
    {
    
$this->iType $iType;
    
$this->sMessage    $sMessage;
    
$this->aBackTrace  $aBackTrace;
    
$this->sFile $sFile;
    
$this->sLine $sLine;
    }
  
  static function 
create ($iType $sMessage)
    {
    
// get BackTrace, File, Line ...
    
return (new MyError ($iType $sMessage $aBackTrace $sFile $sLine));
    }
  
  public function 
log ()
    {
    
$sMessage sprintf (self::$sFormat    ,
                         
$this->iType      ,
                         
$this->sMessage   ,
                         
$this->aBackTrace ,
                         
$this->sFile      ,
                         
$this->sLine      ,
                         
date ('Y-m-d H:i:s') );
    
// check log file ...
    
error_log ($sMessage self::$sLogfile);
    }
  }
?
Wie man sieht ist die Definition des Klassenmembers $sFormat sehr kryptisch und nicht gerade intuitiv. Will man das Format ändern, muß man sich stets die jeweiligen Indexe der Attribute der sprintf () Funktion heraussuchen. Noch schlimmer: Die Indexe der Parameter sind dazu abhängig von der log () Methode, sind hier quasi fest verdrahtet.

Ziel ist ein adäquater Ersatz für sprintf (), der im Formatstring eine klare Aussage über den einzusetzenden Parameter macht. Im Endeffekt eine Art Template.
Wobei die eigentliche Funktionalität der Parameter von printf () erhalten werden soll, also z.B. die explizite Typumwandlung eines Parameters nach int, führende Nullen oder Leerzeichen etc.


Lösung

Zunächst die Funktion, die ich vsprintf_assoc () getauft habe. Genauso denkbar wären natürlich Pendants für printf (), vprintf () und vsprintf ():

PHP-Code:
<?
define 
('nCore_PRINT_FORMATTED_TAG_MIN_LENGTH' 1);

/*
string = vsprintf_assoc (string Format , array Settings)

    Liefert einen formatierten String, dessen Platzhalter mit Werten
    aus Settings gefüllt wurden. Die Funktion ist weitgehend identisch
    mit vsprintf (), lediglich die Art der Platzhalter ist anders.

    Die Platzhalter wurden hier zu 'sprechenden' Bezeichnern erweitert,
    die den Schlüsseln des assoziativen Arrays Settings entsprechen. 
    Die Platzhalter-Syntax entspricht derjenigen von printf, die Platzhalter 
    werden durch die jeweiligen Array Schüssel und ein abschließendes % Zeichen 
    ersetzt. Die Funktionalität bleibt erhalten.

    Bsp.

      vsprintf Syntax
      ('%02d Personen namens %s' , array (7 , 'Heinz'));

      vsprintf_assoc Syntax
      ('%02dAnzahl% Personen namens %sName%' , 
       array ('Anzahl' => 7 , 'Name' => 'Heinz'));

    vsprintf_assoc unterstützt auch Array-Werte in beliebiger Dimension. Wichtig
    ist hierbei, die Platzhalterangabe ohne Leerzeichen zwischen Variablennamen 
    und Klammer zu machen (ebenso zwischen Klammern mehrdimensionaler Angaben).

      ('%dAnzahl% Tage: %sTag[0]%, %sTag[1]%' , 
       array ('Anzahl' => 2 , 'Tage' => array ('Montag' , 'Mittwoch')));


    Parameter:            Format       Formatstring, siehe Beschreibung
                                       und printf Syntaxschema
                          Settings     assoziatives Array
    Abhängigkeiten:       nCore_PRINT_FORMATTED_TAG_MIN_LENGTH
                                       definiert die minimale Länge für 
                                       Variablennamen
    Rückgabe:             String mit in die Platzhalter eingesetzten Werten.
    Hinweise:             - Diese Funktion unterstützt kein Argument swapping 
                          im Formatstring (ist ja auch nicht sinnvoll)!
                          - Zur Performancesteigerung generiert die Funktion für
                          jeden neuen Formatstring eine eigene Lambdafunktion,
                          die sie selbst verwaltet.
                          - Auf abschließende % achten! Fehlende % werden mit 
                          einem 'Too few arguments' Warning quittiert
--------------------------------------------------------------------------- */
function vsprintf_assoc ($sFormat $aSettings)
  {
  static 
$aLambda = array ();

  
$sIndex md5 ($sFormat);

  
# -- passende Lambda Funktion noch nicht vorhanden
  
if (false === isset ($aLambda[$sIndex]))
    {
    
# -- Suchpattern für Platzhalter
    
$sPattern '#(%[\-\+]?(?:\s|0|\\\'.)?\-?\d*(?:\.\d+)?[bcdeufFosxX])' .
                
'([_A-Za-z][_A-Za-z0-9]{' 
                
min (nCore_PRINT_FORMATTED_TAG_MIN_LENGTH 0) . 
                
',}(?:\[\d+\]|\[[\\\'\\"][^\\\'\\"]+?[\\\'\\"]\])*)%#';

    
# -- Platzhalter suchen
    
preg_match_all ($sPattern $sFormat $aOrder);

    
# -- Parameterliste für Lambda Funktion zusammenstellen
    #    führendes Komma als Komma zwischen Formatstring und 1. Parameter
    
$sParameters '';
    foreach (
$aOrder[2] as $sVariable)
      {
      
$sParameters .= ',$' $sVariable;
      }

    
# -- Body der Lambda Funktion:
    #    extract ($aSettings);
    #    return (sprintf (...));
    
$sFuncBody 'extract($aSettings); return (sprintf (\'' 
                  
# -- ' escapen
                  
addcslashes (
                              
# -- Platzhalter auf printf Format reduzieren
                              
str_replace ($aOrder[0] , $aOrder[1] , $sFormat) ,
                              
'\'' 
                              
) . 
                  
'\' ' $sParameters '));';

    
# -- Lambda Funktion erstellen und im static Array speichern
    
$aLambda[$sIndex] = create_function ('$aSettings' $sFuncBody);
    }
  
  return (
$aLambda[$sIndex] ($aSettings));
  }
Wie schon beschrieben, werden die printf () üblichen Platzhalter einfach durch den Variablennamen und ein Prozentzeichen ergänzt. Aus %s wird also bspw. %sAlbumtitel%, aus %02d wird %02dTracknummer%.
Diese Platzhalter werden durch einen regulären Audsruck gesucht. Der Ausdruck, den ich für die original printf () Syntax erstellt habe lautet:
Code:
(%[\-\+]?(?:\s|0|\\\'.)?\-?\d*(?:\.\d+)?[bcdeufFosxX])
Selbiger wird durch eine 'Variablen'-Definition ergänzt. Als besonderes Feature werden auch Arrays (numerisch und assoziativ, auch mehrdimensional) unterstützt.
Aus den erkannten Settings wird dann eine Liste von Parameternamen zusammengestellt, der Formatstring selbst wird sprintf () kompatibel 'zurückentwickelt'. Die eigentliche Ersetzung erfolgt dann durch sprintf ().

Für häufige Anwendungem sollte die aufwendige reguläre Suche redzuiert werden. Deshalb wird für jeden neuen Formatstring, der vsprintf_assoc () übergeben wird eine temporäre (sogenannte Lambda-) Funktion erstellt, deren Namen von vsprintf_assoc () selbst statisch verwaltet wird und einem md5 Hash des Formatstrings zugeordnet wird.
Ein erneuter Aufruf mit diesem Format ruft die entsprechende Funktion - gegebenenfalls mit anderen Paranetern - direkt auf, ohne den Formatstring erneut zu interpretieren.


Schauen wir uns abschließend die veränderte Sachlage an:

PHP-Code:
<?
class MyError
  
{
  static 
$sFormat  '%sTimestamp% %sMessage% (error %dType%) in %sFile% line %dLine%'// intuitive Logline format

  // ...
  
public function log ()
    {
    
$sMessage vsprintf_assoc (self::$sFormat    ,
                                array (
'Type'      => $this->iType      ,
                                       
'Message'   => $this->sMessage   ,
                                       
'Backtrace' => $this->aBackTrace ,
                                       
'File'      => $this->sFile      ,
                                       
'Line'      => $this->sLine      ,
                                       
'Timestamp' => date ('Y-m-d H:i:s')));
    
// check log file ...
    
error_log ($sMessage self::$sLogfile);
    }
  }
Möglicherweise nicht das beste Ausgangsbeispiel, aber ich denke der ein oder andere wird eine geeignete Anwendung finden...

Quellen

[1]
http://de2.php.net/manual/en/function.printf.php
http://de2.php.net/manual/en/function.sprintf.php
http://de2.php.net/manual/en/function.vprintf.php
http://de2.php.net/manual/en/function.vsprintf.php
nikosch ist offline   Mit Zitat antworten
Sponsor Mitteilung
PHP Code Flüsterer

Registriert seit: 21.08.2005
Beiträge: 4682
PHP-Kenntnisse:
Fortgeschritten

Alt 15.02.2008, 20:25  
Erfahrener Benutzer
 
Registriert seit: 21.05.2008
Beiträge: 9.937
Zergling-new wird schon bald berühmt werden
Standard

Gefällt mir ganz gut, kopier ich die Tage in meine Lib, wenn hier endlich wieder alles funktioniert. Merci Poste das ganze doch in die User-Notes.
Zergling-new ist offline   Mit Zitat antworten
Alt 15.02.2008, 22:05  
moderatives Dielektrikum
 
Benutzerbild von nikosch
 
Registriert seit: 21.05.2008
Beiträge: 34.248
PHP-Kenntnisse:
Fortgeschritten
nikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz seinnikosch kann auf vieles stolz sein
Standard

Danke für die Blumen...

Kannst ja noch mal drüber schauen. Wie gesagt, gestern erst geschrieben und noch nicht groß getestet. Vielleicht habe ich ja etwas übersehen.

Meinst Du die php.net user notes? Würde ich tun, aber mit meinem Englisch ist's nicht so weit her. Daher auch die deutschen Kommentare.
nikosch ist offline   Mit Zitat antworten
Alt 08.06.2008, 19:15  
Erfahrener Benutzer
 
Benutzerbild von phpdummi
 
Registriert seit: 06.06.2008
Beiträge: 1.631
PHP-Kenntnisse:
Anfänger
phpdummi ist zur Zeit noch ein unbeschriebenes Blatt
Standard

Hallo Niko,

ich habe die Funktion noch nicht ausprobiert, finde sie aber jetzt schon gut!
Intuitiv und einfach zu handhaben. Und die Lesbarkeit wird auch erhöht.

.. Demnächst mal einbauen ..
phpdummi ist offline   Mit Zitat antworten
Antwort


Themen-Optionen
Thema bewerten
Thema bewerten:

Forumregeln
Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are an
Gehe zu

Ähnliche Themen
Thema Autor Forum Antworten Letzter Beitrag
sprintf mittels array füttern? tomtaz PHP Tipps 2008 4 27.03.2008 05:20
Gästebuch auf PHP Basis erstellen - verzweifel ... sanctus PHP Tipps 2006 3 23.04.2006 15:33
Faktura auf PHP Basis für Kleinunternehmer? Trash 5 14.12.2005 08:40
Php Forum auf PHP 5 Basis Beitragsarchiv 4 18.10.2005 20:24
Chat auf Basis von MySQL und PHP??? nicobischof PHP Tipps 2005-2 1 18.10.2005 19:13
Wozu sprintf() ? Chr!s PHP Tipps 2005-2 19 30.07.2005 22:39
parameter für sprintf bzw. string in text umwandeln PHP Tipps 2005-2 4 12.07.2005 15:20
Benötige Hilfe/Tipp für Rechnung mit sprintf PHP Tipps 2005-2 2 03.07.2005 13:50
Texticker auf PHP Basis mit Text aus externer Datei PHP Tipps 2005 2 16.02.2005 15:26
Formatierung mittels sprintf() inu PHP Tipps 2005 3 28.01.2005 16:02
Vertriebs - System auf PHP / MySql Basis dh1sbg Beitragsarchiv 4 18.11.2004 10:20
Warning: sprintf(): Too few arguments Paulo PHP Tipps 2004 3 21.10.2004 12:35

Besucher kamen über folgende Suchanfragen bei Google auf diese Seite
sprintf php, php template sprintf, php sprintf, php sprintf template, php sprintf führende nullen, sprintf platzhalter, printf php reihenfolge, anwendung von sprintf, php printf ersatz, using sprintf for html links, php sprintf platzhalter, php platzhalter printf, warning: vsprintf() [function.vsprintf]: too few arguments in, php printf, printf php, platzhalter printf, php templating sprintf, php parametrisierte strings, php sprintf(\02%, sprintf php reihenfolge

Alle Zeitangaben in WEZ +1. Es ist jetzt 16:17 Uhr.




Powered by vBulletin® Version 3.7.2 (Deutsch)
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.2.0
Aprilia-Forum, Aquaristik-Forum, Liebeskummer-Forum, Zierfisch-Forum, Geizkragen-Forum

Creative Commons License
Dieser Inhalt ist unter einer Creative Commons-Lizenz lizenziert.