Gunther: eval nicht mit mehrdimensionalen Arrays möglich?

Hallo werte Selfgemeinde!

Ich parse ein INI-File mittels parse_ini_file(string $filename [, bool $process_sections ]) und $process_sections = true, sodass ich ein mehrdimensionales Array erhalte.

Nun würde ich die Werte aus diesem Array gerne in einer eval Anweisung verwenden, was aber nicht möglich zu sein scheint.

Da ein Beispiel meistens mehr sagt, als tausend Worte ...:
$ini_array['zweite_gruppe']['pfad'] hat den Wert: "/usr/local/bin"
So liefert das Script die gewünschte Ausgabe:
url: "http://www.example.com/usr/local/bin"

<?php  
$ini_array = parse_ini_file("css/test.ini", true);  
$tmp = $ini_array['zweite_gruppe']['pfad'];  
$str = 'url: \"http://www.example.com$tmp\"';  
eval ("\$str = \"$str\";");  
echo $str . "\n";  
?>

So leider nicht ...,

<?php  
$ini_array = parse_ini_file("css/test.ini", true);  
$str = 'url: \"http://www.example.com$ini_array[zweite_gruppe][pfad]\"';  
eval ("\$str = \"$str\";");  
echo $str . "\n";  
?>

stattdessen erhalte ich:
url: "http://www.example.comArray[pfad]"

Mit einem eindimensionalen Array funktioniert es.

<?php  
$ini_array = parse_ini_file("css/test.ini", true);  
$str = 'url: \"http://www.example.com$ini_array[pfad]\"';  
eval ("\$str = \"$str\";");  
echo $str . "\n";  
?>  

Frage: Ist das prinzipiell nicht möglich (konnte keine konkrete Antwort per Google & Co. finden), oder mach' ich nur etwas falsch?

Für Tipps & Hilfe meinen besten Dank im Voraus.

Gruß Gunther

  1. Hi!

    Frage: Ist das prinzipiell nicht möglich (konnte keine konkrete Antwort per Google & Co. finden), oder mach' ich nur etwas falsch?

    Wie lautet die konkrete Anweisung, die du dem eval() übergibst? Dazu ist es nötig, dass du den PHP-Code nicht direkt im eval() zusammenbaust sondern vorher erst in einer Variablen.

    Wozu brauchst du überhaupt das eval()? Ich sehe zumindest in den Beispielen nichts, was nicht mit Stringverkettung lösbar wäre.

    Lo!

    1. Hi!

      Frage: Ist das prinzipiell nicht möglich (konnte keine konkrete Antwort per Google & Co. finden), oder mach' ich nur etwas falsch?

      Wie lautet die konkrete Anweisung, die du dem eval() übergibst? Dazu ist es nötig, dass du den PHP-Code nicht direkt im eval() zusammenbaust sondern vorher erst in einer Variablen.

      Da ich mir nicht sicher bin, ob ich deine (Nach-)Frage überhaupt richtig verstehe, erläutere ich mal das Vorhaben ansich. Eventuell könntest du mir ja dann einen (anderen) Weg aufzeigen, wie ich es am besten/ einfachsten umsgesetzt bekomme.

      Das, was in den Beispielen in $str steht, soll später der Inhalt einer (eingelesenen) Datei sein. In dieser würde ich eben gerne mein mehrdimensionales Array verwenden.

      Die Werte für dieses sollen aus dem INI-File kommen.

      Und zum Schluss hätte ich gerne die Datei mit den durch die jeweiligen Werte ersetzen Variablen wiederum in einer Variablen (als String) stehen.

      Wozu brauchst du überhaupt das eval()? Ich sehe zumindest in den Beispielen nichts, was nicht mit Stringverkettung lösbar wäre.

      Hmmm ..., hilf' mir mal bitte auf die Sprünge. Scheinterbar ist es schon wieder zu heiß hier - ich kann jedenfalls im Moment (noch) nicht ganz folgen.

      Gruß Gunther

      1. Hi,

        Wozu brauchst du überhaupt das eval()? Ich sehe zumindest in den Beispielen nichts, was nicht mit Stringverkettung lösbar wäre.
        Hmmm ..., hilf' mir mal bitte auf die Sprünge. Scheinterbar ist es schon wieder zu heiß hier - ich kann jedenfalls im Moment (noch) nicht ganz folgen.

        Du sollst auf eval() verzichten, solange Du dafür keinen sehr, sehr, *sehr* guten Grund angeben kannst. In Deinem Code ist definitiv nicht mal der Ansatz einer Notwendigkeit für eval() zu erkennen, eliminiere es also.

        Cheatah

        --
        X-Self-Code: sh:( fo:} ch:~ rl:| br:> n4:& ie:% mo:) va:) de:] zu:) fl:{ ss:) ls:~ js:|
        X-Self-Code-Url: http://emmanuel.dammerer.at/selfcode.html
        X-Will-Answer-Email: No
        X-Please-Search-Archive-First: Absolutely Yes
        1. Hi,

          Du sollst auf eval() verzichten, solange Du dafür keinen sehr, sehr, *sehr* guten Grund angeben kannst. In Deinem Code ist definitiv nicht mal der Ansatz einer Notwendigkeit für eval() zu erkennen, eliminiere es also.

          OK - also eliminiere ich es.
          Ich habe doch in meinem 2. Posting den Anwendungsfall erläutert.

          Wie setze ich das denn dann ohne eval() am besten/ einfachsten/ sinnvollsten um?
          Indem ich die eingelesene Datei Zeile für Zeile durchlaufe und per preg_match nach Variablennamen suche und falls Werte dafür vorhanden sind (aus meiner INI-Datei) diese dann ersetze, oder wie?

          Ich dachte bislang eigentlich immer, dass das u.a. ein Anwendungsfall für eval() ist, weil es die benötigten Scriptzeilen auf ein Minimum reduziert? Wieso sollte man das denn eigentlich nicht verwenden?

          Gruß Gunther

          1. Hi,

            Ich habe doch in meinem 2. Posting den Anwendungsfall erläutert.

            Wie setze ich das denn dann ohne eval() am besten/ einfachsten/ sinnvollsten um?

            mit der dafür vorgesehenen Funktionalität.

            Ich dachte bislang eigentlich immer, dass das u.a. ein Anwendungsfall für eval() ist, weil es die benötigten Scriptzeilen auf ein Minimum reduziert? Wieso sollte man das denn eigentlich nicht verwenden?

            http://www.google.de/search?q=eval+is+evil

            Cheatah

            --
            X-Self-Code: sh:( fo:} ch:~ rl:| br:> n4:& ie:% mo:) va:) de:] zu:) fl:{ ss:) ls:~ js:|
            X-Self-Code-Url: http://emmanuel.dammerer.at/selfcode.html
            X-Will-Answer-Email: No
            X-Please-Search-Archive-First: Absolutely Yes
            1. Hi,

              Ich habe doch in meinem 2. Posting den Anwendungsfall erläutert.

              Wie setze ich das denn dann ohne eval() am besten/ einfachsten/ sinnvollsten um?

              mit der dafür vorgesehenen Funktionalität.

              nicht hauen, aber wie bitte könnte mir serialize() dabei helfen, meine "Platzhalter" in der CSS-Datei zu ersetzen (mit den entsprechenden Werten aus der Ini-Datei)?

              Ich dachte bislang eigentlich immer, dass das u.a. ein Anwendungsfall für eval() ist, weil es die benötigten Scriptzeilen auf ein Minimum reduziert? Wieso sollte man das denn eigentlich nicht verwenden?

              http://www.google.de/search?q=eval+is+evil

              Danke für den Link. Beim "Überfliegen" einiger der Trefferseiten, kam ich jetzt im Wesentlichen zu zwei (Negativ-)Punkten:
              1. Sicherheit
              2. Performance

              Beide tangieren meinen Fall aber nicht im geringsten, denn zu
              1. Die Werte kommen aus einer Ini-Datei, die Datei selber ebenfalls vom eigenen Server, absolut & definitiv 'no user input'!
              2. Auch völlig irrelevant, da das nur bei einer Änderung eines Parameters oder an der CSS-Datei einmal aufgerufen wird, und danach nur jeweils auf die (fertig geparste) gecachte Variante zurückgegriffen wird.

              Hab' ich jetzt etwas vergessen/ übersehen oder noch nicht mitgekriegt?
              Weil das wären jetzt für mich zumindest alles noch keine Punkte, die gegen eine Verwendung in diesem Fall sprechen würden.

              Gruß Gunther

              1. Hab' ich jetzt etwas vergessen/ übersehen oder noch nicht mitgekriegt?

                Der dritte Punkt sollte "Bequemlichkeit" sein.

                Weil das wären jetzt für mich zumindest alles noch keine Punkte, die gegen eine Verwendung in diesem Fall sprechen würden.

                Gewöhne dir diesen äußerst schlechten stil garnicht erst an - das könnte später, wenn es wirklich um Sicherheit oder Performance geht, uncoole folgen haben.

                1. Hi suit!

                  Gewöhne dir diesen äußerst schlechten stil garnicht erst an - das könnte später, wenn es wirklich um Sicherheit oder Performance geht, uncoole folgen haben.

                  Gut, das Argument zieht natürlich immer. ;-)
                  Wenn mir jetzt aber bitte dann noch jemand folgende Fragen beantworten könnte:
                  1. Mein Ausgangsfrage: eval() nicht mit mehrdimensionalen Arrays möglich?
                  2. Wenn ich also nicht eval() verwende, wie mache ich es dann (Cheatas Hinweis serialize() habe ich in dem Zusammenhang nicht begriffen)?

                  Gruß Gunther

                  1. Moin!

                    Gewöhne dir diesen äußerst schlechten stil garnicht erst an - das könnte später, wenn es wirklich um Sicherheit oder Performance geht, uncoole folgen haben.
                    Gut, das Argument zieht natürlich immer. ;-)

                    Das ist überhaupt das ultimative Argument. eval() erzeugt dir eine ganz dicke, klebrige Schicht Indirektheit. Du hast keine direkte Kontrolle mehr über den ausgeführten Code, sondern nur noch über den Codegenerator, der dann eval() füttert. Codefehler werden nicht mehr direkt angemeckert oder von entsprechenden Tools wie Syntaxhighlighting und Analysewerkzeugen entdeckt. Insgesamt verzichtest du auf eine extrem große Bandbreite von sinnvollen Hilfsmitteln, und holst dir eben die Sicherheitsprobleme und Performancenachteile noch zusätzlich ins Boot.

                    1. Mein Ausgangsfrage: eval() nicht mit mehrdimensionalen Arrays möglich?

                    Du nutzt in eval() kein mehrdimensionales Array. Du nutzt einen simplen String:
                    eval ("\$str = \"$str\";");

                    Also kann das Problem nicht mit eval() zusammenhängen.

                    Würdest du dir VOR dem eval() mal $str ausgeben lassen, würdest du sehen, dass dein Ergebnis des eval() auch vor dem eval() schon identisch ist: url: "http://www.example.comArray[pfad]"

                    Was sagt uns das? Offenbar ist beim Stringzusammenbau von $str was schief gelaufen.

                    Und wenn man sich die Doku in PHP ansieht, wird man den Grund auch finden: In doppelten Anführungszeichen kann man nur einfache Variablen direkt verwenden, also z.B. so
                    $str = "url: $irgendwas";

                    Man kann auch eindimensionale Arrays verwenden, wenn man den Array-Index-String OHNE Anführungszeichen schreibt:
                    $str = "url: $irgendwas[index]";

                    Im Gegensatz dazu muss man ja bei Array-Notation außerhalb den Index-String in Anführungszeichen schreiben:
                    $str = $irgendwas['index'];

                    Innerhalb von doppelten Anführungszeichen dürfen komplexere Variablen bzw. auch Objekte nur vorkommen, wenn man sie in geschweifte Klammern setzt:
                    $str = "url: {$irgendwas['index'][2]}";

                    Dann ist aber auch wieder zwingend das Nutzen von Anführungszeichen um den Index-String notwendig!
                    http://php.net/manual/en/language.types.array.php#language.types.array.foo-bar

                    http://www.php.net/manual/en/language.types.string.php#language.types.string.parsing

                    Allerdings sei unbedingt angemerkt, dass die im letzten Link weiter unten beschriebene "complex curly syntax" durchaus ein Einfallstor für Angreifer sein kann. Gerade deswegen ist eval() böse - und nicht nur eval() allein, es gibt noch etliche weitere Funktionen, die das Evaluieren von Code zur Laufzeit durchführen, beispielsweise auch preg_replace() mit dem Modifikator "/e".

                    Wenn ich deinen Code betrachte, tust du im eval() aber nichts anderes, als exakt eine Codezeile davor ebenfalls schon passiert. Es ist also komplett überflüssig.

                    1. Wenn ich also nicht eval() verwende, wie mache ich es dann (Cheatas Hinweis serialize() habe ich in dem Zusammenhang nicht begriffen)?

                    str_replace() beispielsweise.

                    Die CSS-Vorlage liest du mit file_get_contents() in einen String ein, wendest dann str_replace() auf alle darin enthaltenen Platzhalter an, und ersetzt diese durch die Werte, die du aus deiner INI-Datei erhalten hast, und am Ende packst du den erzeugten String irgendwo passend hin - schickst ihn zum Browser, speicherst ihn direkt auf Festplatte, oder in einen Cache.

                    - Sven Rautenberg

                    1. Moin Sven!

                      Vorweg: Vielen Dank für deine sehr ausführliche & hilfreiche Antwort. Außerdem ist so formuliert, dass ich auch folgen kann. ;-)
                      (@dedlfix: Das gilt natürlich auch für deine Antwort!)

                      Gewöhne dir diesen äußerst schlechten stil garnicht erst an - das könnte später, wenn es wirklich um Sicherheit oder Performance geht, uncoole folgen haben.
                      Gut, das Argument zieht natürlich immer. ;-)

                      Das ist überhaupt das ultimative Argument. eval() erzeugt dir eine ganz dicke, klebrige Schicht Indirektheit. Du hast keine direkte Kontrolle mehr über den ausgeführten Code, sondern nur noch über den Codegenerator, der dann eval() füttert. Codefehler werden nicht mehr direkt angemeckert oder von entsprechenden Tools wie Syntaxhighlighting und Analysewerkzeugen entdeckt. Insgesamt verzichtest du auf eine extrem große Bandbreite von sinnvollen Hilfsmitteln, und holst dir eben die Sicherheitsprobleme und Performancenachteile noch zusätzlich ins Boot.

                      ACK. Nach meinem Verständnis ist aber ja gerade mein spezieller Anwendungsfall einer, wo sich genau diese Probleme_nicht_ergeben. Grundsätzlich habe ich die Problematik und die Gefahren schon verstanden. Gut, bleibt die Gefahr der möglichen Gewöhnung.

                      Aber gut, wenn es ja auch anders geht, ohne dass dadurch irgendwelche gravierenden Nachteile entstehen, dann kann man es ebensogut (bzw. besser) gleich anders machen.

                      1. Mein Ausgangsfrage: eval() nicht mit mehrdimensionalen Arrays möglich?

                      Du nutzt in eval() kein mehrdimensionales Array. Du nutzt einen simplen String:
                      eval ("\$str = \"$str\";");

                      Also kann das Problem nicht mit eval() zusammenhängen.

                      Erwischt. Hier ist mir eine sprachliche Ungenauigkeit unterlaufen. Richtig hätte es z.B. so heißen müssen:"In dem zu evaluierenden String möchte ich gerne ...!".

                      Würdest du dir VOR dem eval() mal $str ausgeben lassen, würdest du sehen, dass dein Ergebnis des eval() auch vor dem eval() schon identisch ist: url: "http://www.example.comArray[pfad]"

                      Was sagt uns das? Offenbar ist beim Stringzusammenbau von $str was schief gelaufen.

                      Ja - s.o.

                      Und wenn man sich die Doku in PHP ansieht, wird man den Grund auch finden: In doppelten Anführungszeichen kann man nur einfache Variablen direkt verwenden, also z.B. so
                      $str = "url: $irgendwas";

                      Man kann auch eindimensionale Arrays verwenden, wenn man den Array-Index-String OHNE Anführungszeichen schreibt:
                      $str = "url: $irgendwas[index]";

                      Im Gegensatz dazu muss man ja bei Array-Notation außerhalb den Index-String in Anführungszeichen schreiben:
                      $str = $irgendwas['index'];

                      Innerhalb von doppelten Anführungszeichen dürfen komplexere Variablen bzw. auch Objekte nur vorkommen, wenn man sie in geschweifte Klammern setzt:
                      $str = "url: {$irgendwas['index'][2]}";

                      Dann ist aber auch wieder zwingend das Nutzen von Anführungszeichen um den Index-String notwendig!
                      http://php.net/manual/en/language.types.array.php#language.types.array.foo-bar

                      http://www.php.net/manual/en/language.types.string.php#language.types.string.parsing

                      Allerdings sei unbedingt angemerkt, dass die im letzten Link weiter unten beschriebene "complex curly syntax" durchaus ein Einfallstor für Angreifer sein kann. Gerade deswegen ist eval() böse - und nicht nur eval() allein, es gibt noch etliche weitere Funktionen, die das Evaluieren von Code zur Laufzeit durchführen, beispielsweise auch preg_replace() mit dem Modifikator "/e".

                      Wenn ich deinen Code betrachte, tust du im eval() aber nichts anderes, als exakt eine Codezeile davor ebenfalls schon passiert. Es ist also komplett überflüssig.

                      Hmm ..., ich hab' mich zum testen/ ausprobieren ja erstmal im Prinzip genau an das Beispiel aus der Doku gehalten, nur mit dem Unterschied, dass meine Variablenwerte halt woanders herkommen.

                      1. Wenn ich also nicht eval() verwende, wie mache ich es dann (Cheatas Hinweis serialize() habe ich in dem Zusammenhang nicht begriffen)?

                      str_replace() beispielsweise.

                      Die CSS-Vorlage liest du mit file_get_contents() in einen String ein, wendest dann str_replace() auf alle darin enthaltenen Platzhalter an, und ersetzt diese durch die Werte, die du aus deiner INI-Datei erhalten hast, und am Ende packst du den erzeugten String irgendwo passend hin - schickst ihn zum Browser, speicherst ihn direkt auf Festplatte, oder in einen Cache.

                      Vielen Dank für die sehr verständliche Erklärung!
                      So werde ich es dann machen. Wie dedlfix ja auch schon geschrieben hat, muss ich dann quasi in einem vorherigen Schritt noch dafür sorgen, meine Platzhalter und mein mehrdimensionales Array in ein übereinstimmendes Format zu bringen, richtig?

                      Gruß Gunther

                      1. Hallo,

                        hier mal ein einfaches Beispiel welches kein EVAL() verwendet und Dir evtl. sogar schon ausreichend die gewünschte Funktionalität als Basis liefert:

                          
                        <?php  
                        class Template  
                        {  
                            const VAR_PATTERN         = '~\[([^\]]+)\]~';  
                            const COMMENT_FORMAT      = '/* %s */';  
                            const PATH_DELIMITER      = '.';  
                            const ATTRIBUTE_DELIMITER = ';';  
                            const ATTRIBUTE_ASSIGN    = ':';  
                            const ELEMENT_DELIMITER   = ' ';  
                          
                            public $vars = array();  
                          
                            protected function cbVarPattern($matches)  
                            {  
                                $path = array_reverse(explode(self::PATH_DELIMITER, $matches[1]));  
                                $ref = & $this->vars;  
                                while(!empty($path))  
                                {  
                                    $element = array_pop($path);  
                                    if(isset($ref[$element]))  
                                    {  
                                        $ref = & $ref[$element];  
                                    }  
                                    else  
                                    {  
                                        // unbekannter array index - hier anfangen zu meckern...)  
                                        return sprintf(self::COMMENT_FORMAT, $matches[0]);  
                                        break;  
                                    }  
                                }  
                                return $this->escape($ref);  
                            }  
                          
                            protected function escape($value)  
                            {  
                                if(is_array($value))  
                                {  
                                    reset($value);  
                                    if(is_numeric(key($value)))  
                                    {  
                                        $value = implode(self::ELEMENT_DELIMITER, $value);  
                                    }  
                                    else  
                                    {  
                                        $temp = array();  
                                        foreach($value as $attrName => $attrValue)  
                                        {  
                                            $temp[] = $attrName . self::ATTRIBUTE_ASSIGN . $attrValue;  
                                        }  
                                        $value = implode(self::ATTRIBUTE_DELIMITER, $temp);  
                                    }  
                                }  
                                return $value;  
                            }  
                          
                            public function parse($content)  
                            {  
                                return preg_replace_callback(self::VAR_PATTERN, array($this, 'cbVarPattern'), $content);  
                            }  
                        }  
                        $example = <<< VCSS  
                                body { color:[example1.color]; }  
                                div  { border:[example2]; }  
                                p    { [example3] }  
                                br   { margin:[example3.margin]; }  
                                sup  { color:[some.more.nonsense]; }  
                        VCSS;  
                        $template = new Template();  
                        $template->vars['example1']['color'] = '#C0C0C0';  
                        $template->vars['example2'] = array('1px','solid','red');  
                        $template->vars['example3'] = array('font-size' => '1em', 'margin' => '1em');  
                        var_dump($template, $example, $template->parse($example));  
                        
                        
                        1. Hi!

                          hier mal ein einfaches Beispiel welches kein EVAL() verwendet und Dir evtl. sogar schon ausreichend die gewünschte Funktionalität als Basis liefert:

                          Was dem Beispiel fehlt sind Kommentare über das beabsichtigte Verhalten beziehungsweise die Intentionen hinter einigen Konstrukten.

                          const VAR_PATTERN         = '~[([^]]+)]~';
                              const COMMENT_FORMAT      = '/* %s */';
                              const PATH_DELIMITER      = '.';
                              const ATTRIBUTE_DELIMITER = ';';
                              const ATTRIBUTE_ASSIGN    = ':';
                              const ELEMENT_DELIMITER   = ' ';

                          Welche Aufgaben haben die Konstanten. Besonders die ersten beiden scheinen mir erklärungswürdig, damit man sie anpassen kann, ohne erst mit Codeanalyse ihre Wirkung zu ermitteln.

                          public $vars = array();

                          vars ist nicht gerade ein sprechender Name. Was ist seine Aufgabe? Gibt es einen Namen, der besser zur Aufgabe passt?

                          $path = array_reverse(explode(self::PATH_DELIMITER, $matches[1]));

                          Warum muss das Array umgedreht werden? Kann das eingespart und im weiteren Verlauf array_shift() statt array_pop() verwendet werden?

                          $ref = & $this->vars;

                          Warum wird die Referenz angelegt? Ist das technisch notwendig? PHP ist clever genug, bei einer Variablenzuweisung keine echte Kopie anzulegen, solange es nicht wegen auseinanderlaufender Werte notwendig ist. Auch hier wieder ist ref kein aussagekräftiger Bezeichner.

                          // unbekannter array index - hier anfangen zu meckern...)
                                          return sprintf(self::COMMENT_FORMAT, $matches[0]);

                          Diese Funktionalität sollte in der Funktionsbeschreibung erwähnt werden, damit man erfährt, was mit Platzhaltern ohne Werte passiert. Hier steht zwar ein Kommentar, der aber nicht besonders sinnvoll ist, da er nicht zum Code passt.

                          protected function escape($value)
                              public function parse($content)

                          Auch den beiden kann ein Kommentar zur Arbeitsweise und dem Inhalt der erwarteten Parameter nicht schaden (ebenso wie sprechendere Variablennamen).

                          Als Pluspunkt neben meiner Kritik kann ich aber die Codeformatierung erwähnen.

                          Grundsätzlich ist das mit dem fertigen Code immer so eine Sache. Der hilft dem Empfänger nur auf den ersten Blick. Man kann zwar daraus lernen, besonders wenn er verständlich geschrieben ist, aber die Erfahrung, die man beim Ausdenken des Lösungsweges, beim Recherchieren, Schreiben und Testen des Codes gesammelt hat sind, sind einem selbst zugeflossen und nicht dem Empfänger.

                          Lo!

                          1. Moin!

                            Als Pluspunkt neben meiner Kritik kann ich aber die Codeformatierung erwähnen.

                            Als Negativpunkt kann ich den Codestyle erwähnen.

                            Es ist Usus, sämtliche Methoden, die nicht public sind, mit einem Unterstrich beginnen zu lassen. Daran sollte man sich halten, es macht das Codelesen deutlich leichter.

                            Grundsätzlich ist das mit dem fertigen Code immer so eine Sache. Der hilft dem Empfänger nur auf den ersten Blick. Man kann zwar daraus lernen, besonders wenn er verständlich geschrieben ist, aber die Erfahrung, die man beim Ausdenken des Lösungsweges, beim Recherchieren, Schreiben und Testen des Codes gesammelt hat sind, sind einem selbst zugeflossen und nicht dem Empfänger.

                            Ja, die Klasse tut sehr viel, ohne dabei erklärend zumindest die Nutzungsmöglichkeiten aufzuzeigen. Und insbesondere kollidiert das Pattern der Variablen mit der normalen CSS-Definition der Selektoren für Attribute: p[id] { /* alle P mit ID-Attribut */ } Böse Falle!

                            - Sven Rautenberg

                            1. Hi!

                              Als Negativpunkt kann ich den Codestyle erwähnen.

                              Coding Style ist oftmals eine Frage der persönlichen Preferenz.

                              Es ist Usus, sämtliche Methoden, die nicht public sind, mit einem Unterstrich beginnen zu lassen. Daran sollte man sich halten, es macht das Codelesen deutlich leichter.

                              Und __construct() sowie andere Magic Methodes müssen demnach immer nicht public sein?

                              Die Unterstrichregel ist nicht sinnvoll bei als protected ausgezeichneten Mitgliedern, denn die können in einer abgeleiteten Klasse zu public umdeklariert werden und dann stünden sie da mit ihrem Unterstrich und verwirrten dich beim Codelesen.

                              Lo!

                              1. Moin!

                                Als Negativpunkt kann ich den Codestyle erwähnen.

                                Coding Style ist oftmals eine Frage der persönlichen Preferenz.

                                Nicht, wenn man sich in Universen bewegt, in denen sie vorgeschrieben werden.

                                Es ist Usus, sämtliche Methoden, die nicht public sind, mit einem Unterstrich beginnen zu lassen. Daran sollte man sich halten, es macht das Codelesen deutlich leichter.

                                Und __construct() sowie andere Magic Methodes müssen demnach immer nicht public sein?

                                Nein, diese magischen Methoden haben eine Sonderstellung - außerdem beginnen sie ja auch mit ZWEI Unterstrichen.

                                Die Unterstrichregel ist nicht sinnvoll bei als protected ausgezeichneten Mitgliedern, denn die können in einer abgeleiteten Klasse zu public umdeklariert werden und dann stünden sie da mit ihrem Unterstrich und verwirrten dich beim Codelesen.

                                Wenn ich SOWAS tue, habe ich sowieso Probleme mit meinem Code, nicht nur beim Lesen.

                                Ich hab das gerade mal ausprobiert: Funktioniert unerwarteter Weise tatsächlich - würde ich allerdings nie so realisieren.

                                Wenn ich eine Klasse erweitere, und eine als protected vererbte Methode neu als public implementiere, dann bringt mir das erstmal keinerlei Vorteile, wenn ich den Namen beibehalte. Sprich: Ich kann genausogut auch einen neuen Namen vergeben, ohne Unterstrich. Denn die neue Methode ist ja einfach so aufrufbar, ohne automatisch irgendwie die vererbte Methode aufzurufen.

                                Und der Zugriff auf die vererbte Methode ist in beiden Fällen mittels parent:: möglich, es kommt also nicht zwingend darauf an, dass die neue Methode den gleichen Namen besitzt.

                                - Sven Rautenberg

                                1. Hi!

                                  Die Unterstrichregel ist nicht sinnvoll bei als protected ausgezeichneten Mitgliedern, denn die können in einer abgeleiteten Klasse zu public umdeklariert werden und dann stünden sie da mit ihrem Unterstrich und verwirrten dich beim Codelesen.

                                  Wenn ich SOWAS tue, habe ich sowieso Probleme mit meinem Code, nicht nur beim Lesen.
                                  Ich hab das gerade mal ausprobiert: Funktioniert unerwarteter Weise tatsächlich - würde ich allerdings nie so realisieren.

                                  Und ich stutzte neulich kurz darüber, dass die Sichtbarkeit in C# nicht geändert werden kann.

                                  Wenn ich eine Klasse erweitere, und eine als protected vererbte Methode neu als public implementiere, dann bringt mir das erstmal keinerlei Vorteile, wenn ich den Namen beibehalte. Sprich: Ich kann genausogut auch einen neuen Namen vergeben, ohne Unterstrich. Denn die neue Methode ist ja einfach so aufrufbar, ohne automatisch irgendwie die vererbte Methode aufzurufen.

                                  Die neue überschreibt aber die alte, was ja durchaus nicht unsinnig ist, wenn der alte Klassencode diese Methode anspricht und nun auf meiner neuen, erweiterten/geänderten/korrigierten landen soll. Ansonsten hätte ich in dem Fall zwei Methoden, eine neue unterstrichlose mit der neuen Implementation und eine alte, die den Code der neuen aufruft. Das wird am Ende nicht weniger verwirrend als der falsch gewordene Unterstrich.

                                  Und der Zugriff auf die vererbte Methode ist in beiden Fällen mittels parent:: möglich, es kommt also nicht zwingend darauf an, dass die neue Methode den gleichen Namen besitzt.

                                  Nur wenn man sich innerhalb der Klasse befindet. Von außen geht parent:: natürlich nicht. Irgendwie finde ich das nicht gerade clever, wenn der alte Klassencode _foo() nimmt und ein darauf aufbauendes Projekt foo() verwendet. Kann man dem "alten" Programmierer zum Vorwurf machen, dass er nicht vorausgesehen hat, dass der "neue" die betroffene Funktionalität anders und nun öffentlich haben möchte?

                                  Lo!

                                  1. Hello,

                                    Nur wenn man sich innerhalb der Klasse befindet. Von außen geht parent:: natürlich nicht. Irgendwie finde ich das nicht gerade clever, wenn der alte Klassencode _foo() nimmt und ein darauf aufbauendes Projekt foo() verwendet. Kann man dem "alten" Programmierer zum Vorwurf machen, dass er nicht vorausgesehen hat, dass der "neue" die betroffene Funktionalität anders und nun öffentlich haben möchte?

                                    Ich habe Eure Diskussion hier angespannt verfolgt.
                                    Der Zugriff auf protected Elemente setzt ja mMn auch irgendwie das Lesen der Dokumentation voraus.

                                    Alles, was nachher "öffentlich", also bekanntermaßen leider eher intuitiv, benutzt werden darf, kann ja nach einer Protected-Deklaration nicht mehr erreicht werden. Der Programmierer, der nun meint, er müsse die vorhandene Protected-Methode erweitern, indem er eine neue baut, die die alte nutzt und dann selber öffentlich sein soll, der tut mMn gut daran, ohr einen anderen (erweiterten) Namen zu geben und den führenden Unterstrich wieder wegzunehmen. Soweit reicht denn der Automatismus der impliziten Entwicklungsumgebung von PHP noch nicht.

                                    Würde mich jetzt aber malö interessieren, was andere OOP-Sprachen dazu sagen.

                                    Liebe Grüße aus dem schönen Oberharz

                                    Tom vom Berg

                                    --
                                    Nur selber lernen macht schlau
                                    http://bergpost.annerschbarrich.de
                                    1. Hi!

                                      Würde mich jetzt aber malö interessieren, was andere OOP-Sprachen dazu sagen.

                                      Zu C# schrub ich ja schon, dass da die Sichtbarkeit beim Erben nicht verändert werden kann. Das gilt für Methoden wie für Klassen oder implementierte Interfaces. Wenn beispielsweise die Implementation public sein soll, muss auch das Interface public sein.

                                      Lo!

                                  2. Moin!

                                    Wenn ich eine Klasse erweitere, und eine als protected vererbte Methode neu als public implementiere, dann bringt mir das erstmal keinerlei Vorteile, wenn ich den Namen beibehalte. Sprich: Ich kann genausogut auch einen neuen Namen vergeben, ohne Unterstrich. Denn die neue Methode ist ja einfach so aufrufbar, ohne automatisch irgendwie die vererbte Methode aufzurufen.

                                    Die neue überschreibt aber die alte, was ja durchaus nicht unsinnig ist, wenn der alte Klassencode diese Methode anspricht und nun auf meiner neuen, erweiterten/geänderten/korrigierten landen soll. Ansonsten hätte ich in dem Fall zwei Methoden, eine neue unterstrichlose mit der neuen Implementation und eine alte, die den Code der neuen aufruft. Das wird am Ende nicht weniger verwirrend als der falsch gewordene Unterstrich.

                                    Alles, was in einer Klasse protected oder private ist, ist Bestandteil der internen Implementierung dieser Klasse, und hat den außenstehenden Nutzer der Klasse nicht zu interessieren.

                                    Wenn du jetzt diese Klasse erweitern willst, bist du zwar auch Nutzer, aber kein richtig außenstehender mehr. Und wenn du mit deiner erweiternden Klasse jetzt das Public-Interface um eine neue Methode ergänzen willst, kannst du das ja gern tun. Die Namenskonvention sagt: Public ohne Unterstrich vorneweg.

                                    public function foo (){}

                                    Es bringt dir an diesem Punkt keinerlei Vorteil, die Methode _foo als public zu deklarieren, da du sie dann ja ohnehin implementieren müsstest:
                                    public function _foo () {}
                                    Von alleine ohne Code ruft dir diese Funktion halt nicht automatisch die protected function _foo der Originalklasse auf.

                                    Was diese neue Methode foo tun soll, ist komplett dir überlassen. Wenn sie einfach nur die interne Methode _foo aufrufen soll, damit diese öffentlich verfügbar wird, dann muss sie das tun:

                                    public function foo ()  
                                    {  
                                      return $this->_foo();  
                                    }
                                    

                                    Und wenn dir die Implementation der Originalfunktion _foo in der Originalklasse nicht gefällt, dann baust du dir einfach was eigenes dazu:

                                    protected function _foo () {}

                                    Und wenn diese Methode das Original-_foo aufrufen soll:

                                    protected function _foo ()  
                                    {  
                                      return 'my' . parent::_foo();  
                                    }
                                    

                                    Du hast also wirklich jegliche Möglichkeit, alle denkbaren Konstruktionen zu bauen, ohne dass du die Ordnung des Methoden-Namensraumes durcheinander bringen musst.

                                    Es dreht sich hierbei ja in erster Linie um ein Planungsproblem: Wieso hat der Autor der Originalklasse geplant, dass _foo nur protected ist? Und wieso glaubst du als Autor der Erweiterungsklasse, dass _foo unbedingt public gehört? Und warum ausgerechnet unter diesem Namen?

                                    Nur wenn man sich innerhalb der Klasse befindet. Von außen geht parent:: natürlich nicht. Irgendwie finde ich das nicht gerade clever, wenn der alte Klassencode _foo() nimmt und ein darauf aufbauendes Projekt foo() verwendet. Kann man dem "alten" Programmierer zum Vorwurf machen, dass er nicht vorausgesehen hat, dass der "neue" die betroffene Funktionalität anders und nun öffentlich haben möchte?

                                    Hehe, wenn alle Stricke reißen, kannst du dir immer noch was mit Reflection hinbasteln. ;)

                                    Ich bin persönlich aber absolut kein Fan von sowas. Expliziter Code ist immer besser, als irgendwelche Automagie und der Weg von hinten durch die Brust ins Auge.

                                    - Sven Rautenberg

      2. Hi!

        Frage: Ist das prinzipiell nicht möglich (konnte keine konkrete Antwort per Google & Co. finden), oder mach' ich nur etwas falsch?

        Wie lautet die konkrete Anweisung, die du dem eval() übergibst? Dazu ist es nötig, dass du den PHP-Code nicht direkt im eval() zusammenbaust sondern vorher erst in einer Variablen.

        Hier fehlte noch: ... und dir dessen Inhalt ausgibst.
        Auch eine Kontrollausgabe des Inhalts von $ini_array kann helfen, einen (Denk)fehler zu finden. (var_dump() oder print_r())

        Das, was in den Beispielen in $str steht, soll später der Inhalt einer (eingelesenen) Datei sein. In dieser würde ich eben gerne mein mehrdimensionales Array verwenden.

        Was genau steht in der Datei und was genau verstehst du unter verwenden?

        Wozu brauchst du überhaupt das eval()? Ich sehe zumindest in den Beispielen nichts, was nicht mit Stringverkettung lösbar wäre.
        Hmmm ..., hilf' mir mal bitte auf die Sprünge. Scheinterbar ist es schon wieder zu heiß hier - ich kann jedenfalls im Moment (noch) nicht ganz folgen.

        Unabhängig von deinem jetzigen Lösungswegversuch: Wie lautet die eigentliche Aufgabenstellung? Es gibt dafür vermutlich bessere Wege als Daten in Code umzuwandeln, den dann auszuführen um am Ende Daten zu erhalten.

        Lo!

        1. Hi!

          Das, was in den Beispielen in $str steht, soll später der Inhalt einer (eingelesenen) Datei sein. In dieser würde ich eben gerne mein mehrdimensionales Array verwenden.

          Was genau steht in der Datei und was genau verstehst du unter verwenden?

          Wozu brauchst du überhaupt das eval()? Ich sehe zumindest in den Beispielen nichts, was nicht mit Stringverkettung lösbar wäre.
          Hmmm ..., hilf' mir mal bitte auf die Sprünge. Scheinterbar ist es schon wieder zu heiß hier - ich kann jedenfalls im Moment (noch) nicht ganz folgen.

          Unabhängig von deinem jetzigen Lösungswegversuch: Wie lautet die eigentliche Aufgabenstellung? Es gibt dafür vermutlich bessere Wege als Daten in Code umzuwandeln, den dann auszuführen um am Ende Daten zu erhalten.

          Also, ich möchte mal mit einem Ansatz 'experimentieren', der es mir ermöglicht, in einer CSS-Datei Variablen zu verwenden. Die Werte für diese Variablen sollen aus einer (oder mehreren) INI-Datei kommen.

          Am Ende soll wieder eine "normale" (und valide ;-)) CSS-Datei dabei rauskommen

          Also bei Anforderung einer CSS-Datei wird der Aufruf an ein PHP-Script weitergeleitet. Dieses liest die entsprechende CSS-Datei (noch mit den Variablen) ein, ersetzt diese (durch die Werte aus der INI-Datei) und sendet das Ganze dann mit entsprechendem Header an den Browser.

          Gruß Gunther

          1. Hi!

            Also, ich möchte mal mit einem Ansatz 'experimentieren', der es mir ermöglicht, in einer CSS-Datei Variablen zu verwenden. Die Werte für diese Variablen sollen aus einer (oder mehreren) INI-Datei kommen.
            Am Ende soll wieder eine "normale" (und valide ;-)) CSS-Datei dabei rauskommen

            Das würde ich nicht mit PHP-Variablen machen sondern mit Platzhaltern. Diese lassen sich im eval()-los suchen und ersetzen.

            Wenn du ein Array mit den Platzhaltern als Keys hast, kannst du strtr() in der zweiten Variante verwenden.
            Auch mehrstufige Arrays sind kein großes Problem. Die Platzhalter sehen beispielsweise so aus: <bereich><name1> und <bereich><name2>. Ein
              array("bereich" => array("name1" => "wert1", "name2" => "wert2"))
            müsste nur nach
              array("<bereich><name1>" => "wert1", "<bereich><name2>" => "wert2">);
            umgeformt werden, was mit zwei geschachtelten foreach-Schleifen und etwas Stringbearbeitung geht.

            Also bei Anforderung einer CSS-Datei wird der Aufruf an ein PHP-Script weitergeleitet. Dieses liest die entsprechende CSS-Datei (noch mit den Variablen) ein, ersetzt diese (durch die Werte aus der INI-Datei) und sendet das Ganze dann mit entsprechendem Header an den Browser.

            Wenn du wirklich Variablen nehmen willst, geht es nur mit eval(), was ich aber mit obigem Vorschlag für vermeidbar halte.

            Zum ursprünglichen Problem: Wenn "...$var[foo][bar]..." als Ergebnis "...Array[bar]..." liefert, so ist nur $var[foo] als Variable erkannt worden. Man kann geschweifte Klammern um die Variablen legen, wenn PHP sie nicht eindeutig in einem ""-String erkennt, also "...{$var[foo][bar]}...". Aber wie gesagt, versuch es lieber ohne eval().

            Lo!

            1. Hi!

              Das würde ich nicht mit PHP-Variablen machen sondern mit Platzhaltern. Diese lassen sich im eval()-los suchen und ersetzen.

              Wenn du ein Array mit den Platzhaltern als Keys hast, kannst du strtr() in der zweiten Variante verwenden.
              Auch mehrstufige Arrays sind kein großes Problem. Die Platzhalter sehen beispielsweise so aus: <bereich><name1> und <bereich><name2>. Ein
                array("bereich" => array("name1" => "wert1", "name2" => "wert2"))
              müsste nur nach
                array("<bereich><name1>" => "wert1", "<bereich><name2>" => "wert2">);
              umgeformt werden, was mit zwei geschachtelten foreach-Schleifen und etwas Stringbearbeitung geht.

              Ja, klingt gut. Zumindest verstehe ich den Ansatz und denke, dass ich das auch hinkriegen sollte.

              Zum ursprünglichen Problem: Wenn "...$var[foo][bar]..." als Ergebnis "...Array[bar]..." liefert, so ist nur $var[foo] als Variable erkannt worden. Man kann geschweifte Klammern um die Variablen legen, wenn PHP sie nicht eindeutig in einem ""-String erkennt, also "...{$var[foo][bar]}...". Aber wie gesagt, versuch es lieber ohne eval().

              Ich sag' ja - es ist eindeutig zu warm. Das ist die Antwort auf meine Ausgangsfrage - besten Dank!

              Und da ich (meistens) auf das höre, was mir hier im Forum geraten wird, werde ich es mal ohne eval() probieren. Wobei mir wie gesagt immer noch nicht ganz klar ist, warum man_speziell_in diesem Fall eben nicht eval() verwenden sollte?

              Gruß Gunther

              1. Moin!

                Zum ursprünglichen Problem: Wenn "...$var[foo][bar]..." als Ergebnis "...Array[bar]..." liefert, so ist nur $var[foo] als Variable erkannt worden. Man kann geschweifte Klammern um die Variablen legen, wenn PHP sie nicht eindeutig in einem ""-String erkennt, also "...{$var[foo][bar]}...".

                Es ist falsch, einfach nur geschweifte Klammern drumherum zu machen. Denn die Variante ohne Klammern erkennt den Array-Index als String, während die Variante mit Klammern den Array-Index als undefinierte Konstante erkennt - und dadurch eine Notice geworfen und ein String mit dem Inhalt des Konstantennamens angenommen wird. Alternativ ist die Konstante schon definiert worden, dann wird deren Inhalt verwendet.

                Und da ich (meistens) auf das höre, was mir hier im Forum geraten wird, werde ich es mal ohne eval() probieren. Wobei mir wie gesagt immer noch nicht ganz klar ist, warum man_speziell_in diesem Fall eben nicht eval() verwenden sollte?

                eval() sollte niemals verwendet werden, außer man hat tatsächlich einen speziellen Fall, wo man nicht drumherum kommt. Man verwendet es ungern und nur dann, wenn man wirklich nicht drum herum kommt.

                So ein Fall ist bei dir einfach nicht gegeben. Du brauchst kein eval(), es macht dein Problem nicht leichter, sondern verschleiert es, reichert es mit Sicherheitsproblemen an, drückt die Performance, macht deinen Code extrem schlecht wartbar etc.

                DON'T DO IT. AVOID EVAL()!

                - Sven Rautenberg

                1. Hi!

                  Es ist falsch, einfach nur geschweifte Klammern drumherum zu machen. Denn die Variante ohne Klammern erkennt den Array-Index als String, während die Variante mit Klammern den Array-Index als undefinierte Konstante erkennt - und dadurch eine Notice geworfen und ein String mit dem Inhalt des Konstantennamens angenommen wird. Alternativ ist die Konstante schon definiert worden, dann wird deren Inhalt verwendet.

                  Danke für die Richtigstellung. Diese Parserei bei komplexen Gebilden ist auch noch komplex und etwas verwirrend implementiert.

                    $foo = $bar['qux']; // mit Anführungszeichen  
                    $foo = "... $bar[qux]..."; // ohne Anführungszeichen  
                    $foo = "... {$bar['qux']}..."; // wieder mit Anführungszeichen
                  

                  Als Alternative kann man sich der Patzhalter-Funktion sprintf() bedienen:

                  $foo = sprintf('...%s...', $bar['qux']);

                  Übrigens: Beim Entwickeln das error_reporting auf E_ALL stehen zu haben, hilft obige Fehler zu erkennen und zu korrigieren.

                  Lo!

  2. Hello,

    vielleicht solltest Du einfach mal deine beiden Dateien, die Du zusammenführen willst, hier exemplarisch vorstellen, also wzei kleinen Beispiele posten, die auch zusammenpassen, Vergiss auch nicht, das von Dir gewünschte Ergebnis mitzusenden...

    Es sollte eigentlich zum Schluss dabei heraus kommen, dass str_ireplace() oder str_replace() die passende Funktion für Dich ist. http://de3.php.net/manual/en/function.str-ireplace.php

    Liebe Grüße aus dem schönen Oberharz

    Tom vom Berg

    --
    Nur selber lernen macht schlau
    http://bergpost.annerschbarrich.de
    Den obligatorischen (Ab-)Satz mit Uschi und Wolle verkneife ich mir diesmal