Struppi: sprintf ein array übergeben.

ich versuch mich heute ein bisschen an PHP und bin jetzt auf ein Problem gestossen dass ich nicht lösen kann.

Ich zeig mal einfach was ich machen will.

  
class Texte {  
 var $msg = array(  
 'text1' => 'Der Text: %s',  
 'text2' => 'Der Text %s hat %s Zeichen.'  
 );  
  
 function _() {  
  $args = func_get_args();  
  $what = array_shift($args);  
  return sprintf($this->msg[$what], $args);  
 }  
}  
  
$t = new Texte();  
$string = 'Hallo Welt!';  
echo $t->_('text1', $string);  
echo $t->_('text2', $string, strlen($string));  

Das geht natürlich nicht, macht aber eventuell deutlich was ich möchte.

In Perl würde die Funktion so aussehen:

sub _() {  
my $this = shift;  
my $args = shift;  
return sprintf($this->{msg}->{$what}, @_);  
}  

Aber wie mache ich das mit PHP?

Struppi.

  1. Hallo

    Ich zeig mal einfach was ich machen will.
    [code lang=php]
    class Texte {
    var $msg = array(
    'text1' => 'Der Text: %s',
    'text2' => 'Der Text %s hat %s Zeichen.'
    );

    function _() {

    // Welche Parameter?
    // Wenn eine Funktion keine erwartet, dann kann sie auch keine bekommen

    $args = func_get_args();
      $what = array_shift($args);
      return sprintf($this->msg[$what], $args);
    }
    }

    [...] *schüttel*, schlimm.

    Das geht natürlich nicht, macht aber eventuell deutlich was ich möchte.

    In Perl würde die Funktion so aussehen:

    Perls Umgang mit Funktionen und Funktionsparametern fand ich stets sehr gewöhnungsbedürftig. Vielleicht habe ich mich deswegen nie richtig mit dieser Programmiersprache anfreunden können.

    Aber wie mache ich das mit PHP?

    Vielleicht hilft Dir dieser Archivthread weiter.

    Freundliche Grüße

    Vinzenz

    1. Hallo

      Ich zeig mal einfach was ich machen will.
      [code lang=php]
      class Texte {
      var $msg = array(
      'text1' => 'Der Text: %s',
      'text2' => 'Der Text %s hat %s Zeichen.'
      );

      function _() {

      // Welche Parameter?
      // Wenn eine Funktion keine erwartet, dann kann sie auch keine bekommen

      Natürlich erwartet die Funktion Parameter.

      $args = func_get_args();
        $what = array_shift($args);

      einen für den Schlüssel des Arrays

      return sprintf($this->msg[$what], $args);

      und beliebig viele die dann an sprintf weiter gereicht um den enstpechenden Text auszugeben.

      }
      }

      [...] *schüttel*, schlimm.

      Keine Ahnung was du da jetzt so schlimm findest, dass ist eine sehr elegante Methode um z.b. verschieden sprachige Texte auszugeben, wo z.b. bestimmte Werte ersetzt werden müssen z.b.

      sprintf 'Ein Fehler: %s", 'meldung';
      sprintf 'Fehler in Datei %s in Zeile %s", 'test.php', 72;
      sprintf 'unbekannter Fehler";

      wie du siehst, sind auch hier variable Parameteranzahl möglich, also eine normale Sache.

      Das geht natürlich nicht, macht aber eventuell deutlich was ich möchte.

      Ich dachte ich hätte das :-(

      In Perl würde die Funktion so aussehen:

      Perls Umgang mit Funktionen und Funktionsparametern fand ich stets sehr gewöhnungsbedürftig. Vielleicht habe ich mich deswegen nie richtig mit dieser Programmiersprache anfreunden können.

      In dem Fall ist PHP gewöhnungsbedürftig, zumindest für mich, da es keinen Weg gibt zu sagen ob man ein Array oder ein Skalar hat, PHP macht hier keinen Unterschied

      Aber wie mache ich das mit PHP?

      Vielleicht hilft Dir dieser Archivthread weiter.

      Nö, das Problem ist ja nicht dass ich nicht weiß wie ich an die Parameter kommen, sondern wie ich PHP sage, dass ich ein Array an sprintf übergeben will und keinen Skalar.

      Struppi.

      1. Hallo Struppi,

        Nö, das Problem ist ja nicht dass ich nicht weiß wie ich an die Parameter kommen, sondern wie ich PHP sage, dass ich ein Array an sprintf übergeben will und keinen Skalar.

        das geht meines Wissens nicht, nutze doch vprintf().

        Freundliche Grüße

        Vinzenz

        1. das geht meines Wissens nicht, nutze doch vprintf().

          Schade, das wäre es gewesen, aber die Funktion gibt den String direkt aus, ich will ihn ja nur zurückgeben :-(

          Struppi.

          1. Hallo Struppi,

            das geht meines Wissens nicht, nutze doch vprintf().

            Schade, das wäre es gewesen, aber die Funktion gibt den String direkt aus, ich will ihn ja nur zurückgeben :-(

            Du stellst Dich heute nicht sehr geschickt an[1]: Der Link zu vsprintf() befindet sich doch in unmittelbarer Nähe ...

            Freundliche Grüße

            Vinzenz

            [1] Die PHP-Dokumentation scheint Dir noch fremd zu sein :-)

            1. das geht meines Wissens nicht, nutze doch vprintf().

              Schade, das wäre es gewesen, aber die Funktion gibt den String direkt aus, ich will ihn ja nur zurückgeben :-(

              Du stellst Dich heute nicht sehr geschickt an[1]: Der Link zu vsprintf() befindet sich doch in unmittelbarer Nähe ...

              Oh Mann übersehen, Danke.

              [1] Die PHP-Dokumentation scheint Dir noch fremd zu sein :-)

              Ich hab drei Tabs mit der Doku offen, da ich ja kein PHP kann muss ich die ganze Zeit nach jedem Befehl schauen. Ich hatte sogar runtergescrollt, aber irgendwie dieses vsprintf übersehen. Naja, bei den drei Millionen PHP Funktionen kann man schon mal was übersehen.

              Struppi.

              1. Hallo Struppi,

                Naja, bei den drei Millionen PHP Funktionen kann man schon mal was übersehen.

                wie findest Du Dich dann bei CPAN zurecht?

                Freundliche Grüße

                Vinzenz

                1. Naja, bei den drei Millionen PHP Funktionen kann man schon mal was übersehen.

                  wie findest Du Dich dann bei CPAN zurecht?

                  Mit der Suchfunktion - aber hier war für mich ein syntaktisches Problem, es gibt eine Funktion die ein variable Anzahl von Parametern erwartet und ich bin noch nicht soweit in PHP das ich mir vorstellen konnte, dass PHP für jede Art von Parameter eine Funktion anbietet, da werd ich in Zukunft genauer nachschauen. Das blöde war, dass halt bei sprintf kein Hinweis auf diese Funktion ist (ausser in den Kommentaren, wenn man weiß wonach man suchen muss).

                  Struppi.

                  1. echo $begrüßung;

                    Das blöde war, dass halt bei sprintf kein Hinweis auf diese Funktion ist (ausser in den Kommentaren, wenn man weiß wonach man suchen muss).

                    Tja, der alte Trick der unaktuellen Übersetzung. Nimm die originale Dokumentation zu sprintf(), da gibt es auch einen "See also"-Abschnitt.

                    echo "$verabschiedung $name";

                    1. Tja, der alte Trick der unaktuellen Übersetzung. Nimm die originale Dokumentation zu sprintf(), da gibt es auch einen "See also"-Abschnitt.

                      Gut zu Wissen. Für mich ist es aber nicht alt, ich habe mich heute das erste mal intensiver mit PHP beschäftigt.

                      Struppi.

  2. Hellihello Struppi,

    mal blöd gefragt: was in Worten willst Du denn erreichen? Zugegebender Maßen habe ich bisher noch keine Verwendungsnotwendigkeiten für sprintf() gefunden.

      
    <?php  
    class Texte {  
    var $msg = array(  
      'text1' => 'Der Text: %s',  
      'text2' => 'Der Text %s hat %s Zeichen.'  
    );  
      
    function _() {  
     $args = func_get_args();  
     $what = array_shift($args);  
     return sprintf($this->msg[$what], array_shift($args),array_shift($args));  
     }  
    }  
      
    $t = new Texte();  
    $string = 'Hallo Welt!';  
    echo $t->_('text1', $string);  
    echo $t->_('text2', $string, strlen($string));  
    ?>  
    
    

    Wie wärs mit

      
    <?php  
    $string = "Hallo Welt";  
    $texte[] = $string;  
    $texte[] = array($string, strlen($string));  
    ?>  
      
    <!--eventuell includiert: -->  
      
    <?php foreach ($texte as $text):;?>  
    <?php if (is_string($text)):; ?>  
     <p>Der Text: <?php echo $text;?></p>  
    <?php elseif (is_array($text)):; ?>  
     <p>Der Text: <?php echo $text[0];?> hat <?php echo $text[1];?> Zeichen</p>  
    <?php endif;?>  
    <?endforeach;?>  
    
    

    Dank und Gruß,

    frankx

    --
    tryin to multitain  - Globus = Planet != Welt
    1. mal blöd gefragt: was in Worten willst Du denn erreichen?

      Ich möchte erreichen, dass ich Texte u.U. in verschiedenen Sprachen einsetzen kann. Ich könnte natürlich auch gettext verwenden, aber da ich das nur für eine kleine Sache zum lernen einsetzen will, wollte ich mir keinen allzu grossen Aufwand machen.

      vsprintf ist dafür auch genau die Lösung:

      class Texte {  
      var $msg = array(  
        'text1' => 'Der Text: %s',  
        'text2' => 'Der Text %s hat %s Zeichen.'  
      );  
        
      function _() {  
       $args = func_get_args();  
       $what = array_shift($args);  
       return vsprintf($this->msg[$what], $args);  
       }  
      }  
        
      $t = new Texte();  
      $string = 'Hallo Welt!';  
      echo $t->_('text1', $string);  
      echo $t->_('text2', $string, strlen($string));  
      
      

      $msg muss man natürlich auslagern z.b. msg.de.php oder msg.en.php usw. wobei mir aber noch nicht klar ist wie das mit PHP am besten geht

      Struppi.

      1. Hellihello Struppi,

        hinkt denn nicht das Beispiel, weil Du hier aus einem Datum zwei Aspekte (string, length) benutzt? Du musst im Template ja sowieso immer wissen, wieviele Paramter übergeben werden.

        Ich habe mittlerweile den Eindruck, dass PHP seine Stärke wirklich als Templatesprache hat. Also die Variablen erst mit Inhalt füllen, und dann html-snippets/templates gespickt mit <?php echo $varnameXyz;?> einbinden. Genau diese Templates musst Du sonst wie unten in Hochkommas im Quelltext ohne Syntaxhighlighting (für html) verpacken, was bei etwas längeren Textstücken schnell unübersichtlich werden kann. Oder anders: mit o.g. Schema inklusive alternativer Syntax für if,foreach,while,for auch bei kleineren Schnipseln übersichtlicher ist.

        Zeigt sich natürlich erst am konkreten Beispiel in der Regel.

        Dank und Gruß,

        frankx

        --
        tryin to multitain  - Globus = Planet != Welt
        1. hinkt denn nicht das Beispiel, weil Du hier aus einem Datum zwei Aspekte (string, length) benutzt? Du musst im Template ja sowieso immer wissen, wieviele Paramter übergeben werden.

          Wieso? Du musst wissen ob ein Text ein oder zwei oder x- Parameter haben muss, dass kann beliebig sein, aber für den bestimmten Text ist es definiert. Hier geht es nicht um ein Template, sondern Systemmeldungen.

          z.b.

          var $msg = array(  
            'FILE_OPEN' => 'Datei "%s" konnte nicht geöffnet werden, weil: %s',  
            'TEXT_TOO_BIG' => 'Der Text "%s" hat %s Zeichen, darf aber nur %s Zeichen haben',  
            'NO' => 'Aktion ist nicht erlaubt',  
          ... usw  
          );
          

          Die Meldungen tauchen natürlich nicht im Template auf, sondern werden damit befüllt
          $this->template->set('error', $this->text->_('FILE_OPEN', $file, ???));

          (ich weiß auch noch nicht, wie man an die Fehlermeldung kommt warum ein fopen() fehlgeschlagen ist, in Perl gibt es dafür die Variabel $!, aber das krieg ich noch raus, steht wahrscheinlich in der englischen Doku)

          Struppi.

          1. Hellihello Struppi,

            hinkt denn nicht das Beispiel, weil Du hier aus einem Datum zwei Aspekte (string, length) benutzt? Du musst im Template ja sowieso immer wissen, wieviele Paramter übergeben werden.

            Wieso? Du musst wissen ob ein Text ein oder zwei oder x- Parameter haben muss, dass kann beliebig sein, aber für den bestimmten Text ist es definiert. Hier geht es nicht um ein Template, sondern Systemmeldungen.

            z.b.

            var $msg = array(

            'FILE_OPEN' => 'Datei "%s" konnte nicht geöffnet werden, weil: %s',
              'TEXT_TOO_BIG' => 'Der Text "%s" hat %s Zeichen, darf aber nur %s Zeichen haben',
              'NO' => 'Aktion ist nicht erlaubt',
            ... usw
            );

              
            Jau, gehen tut das natürlich auch.  
            
            >   
            > Die Meldungen tauchen natürlich nicht im Template auf, sondern werden damit befüllt  
            > `$this->template->set('error', $this->text->_('FILE_OPEN', $file, ???));`{:.language-php}  
              
            Logisch, im Template wären ja auch Textversatzstücke gespickt mit Variablen-Echos, die u.U. dann vom Namen her schon etwas aussagekräfter wären als "%s". Vermutlich ists aber auch eine Frage dessen, was man schon gewohnt ist.  
              
            
            >   
            > (ich weiß auch noch nicht, wie man an die Fehlermeldung kommt warum ein fopen() fehlgeschlagen ist, in Perl gibt es dafür die Variabel $!, aber das krieg ich noch raus, steht wahrscheinlich in der englischen Doku)  
              
            Was haben denn die Fehlermeldungen mit fopen() zu tun? Du kennst PHP file\_get/put\_contents() und auch un/serialize()?  
              
            Dank und Gruß,  
              
            [frankx](http://community.de.selfhtml.org/visitenkarten/view.php?key=82)
            
            -- 
            [tryin to](http://sauer-ernst.de) [multitain](http://multitain.de)  - Globus = Planet != Welt 
            
            1. var $msg = array(

              'FILE_OPEN' => 'Datei "%s" konnte nicht geöffnet werden, weil: %s',
                'TEXT_TOO_BIG' => 'Der Text "%s" hat %s Zeichen, darf aber nur %s Zeichen haben',
                'NO' => 'Aktion ist nicht erlaubt',
              ... usw
              );

              
              >   
              > Jau, gehen tut das natürlich auch.  
              > >   
              > > Die Meldungen tauchen natürlich nicht im Template auf, sondern werden damit befüllt  
              > > `$this->template->set('error', $this->text->_('FILE_OPEN', $file, ???));`{:.language-php}  
              >   
              > Logisch, im Template wären ja auch Textversatzstücke gespickt mit Variablen-Echos, die u.U. dann vom Namen her schon etwas aussagekräfter wären als "%s". Vermutlich ists aber auch eine Frage dessen, was man schon gewohnt ist.  
                
              Der Name ist ja z.b. 'FILE\_OPEN\_ERROR' das halte ich für aussagekräftig, die %s sind ja nur die Platzhalter im String den ich gar nicht mehr sehe.  
                
              Mir ist aber nicht klar, wie du das mit einem Templatesystem lösen würdest.  
                
              
              > >   
              > > (ich weiß auch noch nicht, wie man an die Fehlermeldung kommt warum ein fopen() fehlgeschlagen ist, in Perl gibt es dafür die Variabel $!, aber das krieg ich noch raus, steht wahrscheinlich in der englischen Doku)  
              >   
              > Was haben denn die Fehlermeldungen mit fopen() zu tun? Du kennst PHP file\_get/put\_contents() und auch un/serialize()?  
                
              Was das jetzt damit zu tun hat, dass wenn ich ein fopen mache und es dabei zu einem Fehler kommt und dies ausgeben möchte, weiß ich auch nicht. Die Meldungen waren ein Beispiel für Fehler die auftreten, es gibt ja viele Stellen wo man gerne Fehlermeldungen ausgeben möchte, irgendwie glaube ich dir ist immer noch nicht so ganz klar was ich mit meiner Text Klasse machen möchte.  
                
              Struppi.
              
              1. Hellihello Struppi,

                Der Name ist ja z.b. 'FILE_OPEN_ERROR' das halte ich für aussagekräftig, die %s sind ja nur die Platzhalter im String den ich gar nicht mehr sehe.

                In der Ausgabe nicht (;-). Aber beim basteln schon, oder?

                Mir ist aber nicht klar, wie du das mit einem Templatesystem lösen würdest.

                  
                //Testvar:  
                $_GET["Name"] = "EinZulangerNameIstDas";  
                //fehlerliste  
                $fehler_liste = array();  
                $max_lenght_name = 20;  
                if (strlen($_GET["Name"]) > $max_lenght_name) {  
                 $fehler_liste[] = "name_zu_lang";  
                }  
                $file_name = "abc.txt";  
                if (!file_exists($file_name)) {  
                 $fehler_liste[] = "file_gibts_nicht";  
                }  
                //default test  
                $fehler_liste[] = "fehler_xyz";  
                ?>  
                <ul>  
                <?php foreach ($fehler_liste as $fehler):;?>  
                 <?php switch ($fehler):  
                  case "name_zu_lang":;?>  
                  <li>  
                  Fehler: <?php echo $fehler;?>. Die Eingabe "<?php echo $_GET["Name"];?>" hat <?php echo strlen($_GET["Name"]);?> Zeichen. <?php echo $max_lenght_name; ?> sind erlaubt.  
                  </li>  
                  <?php break;?>  
                  <?php case "file_gibts_nicht":;?>  
                  <li>  
                  Fehler: <?php echo $fehler;?>. Datei <?php echo $file_name;?> nicht vorhanden.  
                  </li>  
                  <?php break;?>  
                  <?php default:;?>  
                  <li>  
                  Fehler: <b style="color:red">"<?php echo $fehler;?>"</b> unbekannt.  
                  </li>  
                  <?php break;?>  
                 <?php endswitch;?>  
                <?php endforeach;?>  
                </ul>  
                  
                
                

                Vom Prinzip hier. Die Fehlerliste könnte includiert werden?

                Was das jetzt damit zu tun hat, dass wenn ich ein fopen mache und es dabei zu einem Fehler kommt und dies ausgeben möchte, weiß ich auch nicht.

                (;-). Na, vieleicht erst schauen, obs das Ding überhaupt gibt? Und dann vielleicht doch schauen, ob unserialize(file_get_contents("data1.ser")) besser den Zweck erfüllen könnte?

                Die Meldungen waren ein Beispiel für Fehler die auftreten, es gibt ja viele Stellen wo man gerne Fehlermeldungen ausgeben möchte, irgendwie glaube ich dir ist immer noch nicht so ganz klar was ich mit meiner Text Klasse machen möchte.

                Das mag gut sein. Am Beispiel sieht mans ja, obs danneben liegt oder nicht.

                Dank und Gruß,

                frankx

                --
                tryin to multitain  - Globus = Planet != Welt
                1. Hellihello Struppi,

                  Der Name ist ja z.b. 'FILE_OPEN_ERROR' das halte ich für aussagekräftig, die %s sind ja nur die Platzhalter im String den ich gar nicht mehr sehe.

                  In der Ausgabe nicht (;-). Aber beim basteln schon, oder?

                  was heißt basteln? In einer einzigen Funktion, die man normalerweise gar nicht zu Gesicht bekommt.

                  Vom Prinzip hier. Die Fehlerliste könnte includiert werden?

                  Vom Prinzip würde ich es so lösen, wobei ich eine Template Klasse verwende, momentan für die einfach Sache hab ich mir bTemplate ausgesucht.

                  <?php  
                  $lang = 'de';  
                  require_once("Texte.$lang.class.php");  
                  require_once('bTemplate.php');  
                    
                  $texte = new Texte();  
                  $tmpl = new bTemplate();  
                    
                  //fehlerliste  
                  $errors = array();  
                  //Testvar:  
                  $_GET["Name"] = "EinZulangerNameIstDas";  
                  $max_lenght_name = 20;  
                    
                  if (strlen($_GET["Name"]) > $max_lenght_name) {  
                   $errors[] = $texte->_('STRING_TOO_LONG', $_GET["Name"], strlen($_GET["Name"]), $max_lenght_name);  
                  }  
                    
                  $file_name = "abc.txt";  
                  if (!file_exists($file_name)) {  
                   $errors[] = $texte->_('FILE_NOT_EXIST', $file_name);  
                  }  
                  //default test  
                  $errors[] = $texte->_('UNKNOWN', 'fehler_xyz');  
                    
                  $tmpl->set('error', $errors);  
                  echo $tmpl->fetch('error.html');  
                  ?>
                  

                  Texte.de.class.php

                  class Texte {  
                  var $msg = array(  
                    'STRING_TOO_LONG' => 'Die Eingabe "%s" hat %s Zeichen. %s sind erlaubt.',  
                    'FILE_OPEN' => '%s. Datei %s nicht vorhanden',  
                    'FILE_NOT_EXIST' => 'Datei %s nicht vorhanden',  
                    'UNKNOWN' => '"%s" unbekannt.',  
                  );  
                  function _() {  
                   $args = func_get_args();  
                   $what = array_shift($args);  
                   return vsprintf($this->msg[$what], $args);  
                   }  
                  }
                  

                  Das Template:

                  <ul>  
                  <loop:error>  
                  <li><tag:error[] /></li>  
                  </loop:error>  
                  </ul>
                  

                  Der Punkt ist, Texte.de.class.php kann ich jederzeit austauschen z.b. gegen Texte.en.class.php oder Texte.fr.class.php und leicht bearbeiten, ich brauch dort kein HTML Code.

                  Was das jetzt damit zu tun hat, dass wenn ich ein fopen mache und es dabei zu einem Fehler kommt und dies ausgeben möchte, weiß ich auch nicht.

                  (;-). Na, vieleicht erst schauen, obs das Ding überhaupt gibt?

                  Das ist ja nur eine Möglichkeit warum fopen fehl schlagen kann, wie gesagt ich kenn das nur von Perl, da habe ich in $! die Meldung warum open nicht funktioniert hat und brauch nicht extra auf die existenz zu prüfen, aber wenn es nicht anders geht, werd ich das so machen müssen.

                  Das mag gut sein. Am Beispiel sieht mans ja, obs danneben liegt oder nicht.

                  Zumindest was das Templatesystem angeht, ich denke noch mal drüber nach.

                  Struppi.

                  1. Hellihello Struppi,

                    kurzes suchen "php ist eine templatesprache" brachte mich zu http://www.inside-php.de/tutorial/PHP-Fortgeschrittene-11/eigenes-Template-System.html

                    Habs nicht im Detail durchgelesen jetzt, aber beim Überfliegen gesehen, dass die Wesentlichen Punkte, die ich u.a. durch ein/zwei Artikel dieser Art und auf der Recherche nach einer TemplateEngine/Framework, dann für mich abgespeichert hatte.

                    was heißt basteln? In einer einzigen Funktion, die man normalerweise gar nicht zu Gesicht bekommt.

                    Eben, dann ist das o.g. vielleicht auch overdone.

                    Vom Prinzip hier. Die Fehlerliste könnte includiert werden?

                    Der Punkt ist, Texte.de.class.php kann ich jederzeit austauschen z.b. gegen Texte.en.class.php oder Texte.fr.class.php und leicht bearbeiten, ich brauch dort kein HTML Code.

                    Das ist ja nur eine Möglichkeit warum fopen fehl schlagen kann, wie gesagt ich kenn das nur von Perl, da habe ich in $!

                    Klingt gut. PHP produziert ein WARNING, was eben je nach Einstellung des error_reporting() dann ausgegeben wird.

                    Meines Wissens ist ja PHP in Kenntnis von Perl entstanden. So gehe ich, ohne es nachprüfen zu können - da ich Perl nicht kenne - prinzipiell davon aus, dass es im zweckgebundenen Einsatz alles nötige von Perl können müsste, bzw. an manchen Ecken eben mehr, sonst hätten die Jungs sich ja kaum die Mühe gemacht, und gleich Perl benutzt. Perl ist ja aus dem selbem Grund enstanden, weil Larry Wall (?) sed und awk nicht ausreichten.

                    Dank und Gruß,

                    frankx

                    --
                    tryin to multitain  - Globus = Planet != Welt