2016-06-26 5 views
2

Ich bin derzeit Refactoring Code von einer Seite Parser-Funktion zu OOP. Ich habe Schwierigkeiten mit und Ausführen von Code aus einer Datei in dem Haupt Funktionsumfang:Wie Code aus enthaltenem Dateipfad des Objekts in Funktionsumfang außerhalb des Objekts ausführen?

Objekt:

class phpFragment { 
    private $sData; 

    function render() { 
     return include $oElement->sData; 
    } 
} 

Object Container-Klasse:

class pageData { 
    protected $aPhpFragments; 
    protected $aCssFragments; 

    public function outputData($sTag) { 
     switch($sTag) { 
      case 'php': 
       foreach($this->aPhpFragments as $oPhpFragment) { 
        return $oPhpFragment->render(); 
       } 
       break; 
      case 'css': 
       foreach($this->aCssFragments as $oCssFragment) { 
        echo $oCssFragment->render(); 
       } 
       break; 
     } 
    } 
} 

Hauptfunktion:

function parsePage($sLanguageCode) { 
    $oTranslator = new translator($sLanguageCode); 
    $aTranslations = $oTranslator->translations('page'); 
    $oBuilderClass = new builder($aTranslations); 

    //... queries to get data and set pagedata and get the template file 
    $oPageData = $oPage->getData(); 
    $aTemplateTags = $oTemplate->getTags(); 
    foreach($aTemplateTags as $sTag) { 
     $oPageData->outputData($sTag); 
    } 

    //.... 
} 

Code von enthalten (Beispiel):

Ich möchte die Builder-Klasse nur einmal initiieren, weil sie ziemlich viele Daten enthält, und ich möchte das nicht auf jedem Include neu erstellen.

Wie kann ich den Code des Include in die parsePage-Funktion zurückgeben, wo die Builder-Klasse verwendet werden kann?

+0

Sie erwähnen ein Include in der 'render()' -Funktion am oberen Rand der Seite ist dies der Inhalt, den Sie am Ende der Seite anzeigen? Ist das das Gleiche? Die '$ oBuilderClass' wird in der 'parsePage'-Funktion generiert, aber im Include referenziert, so dass sie mir ziemlich verwirrt erscheint. – Martin

+0

" Wie kann ich den Code des Include in die parsePage-Funktion zurückgeben "welche Include? Meinst du, du willst die Klasse 'Builder' nur einmal instanziieren, d. das [Singleton-Muster] (https://en.wikipedia.org/wiki/Singleton_pattern), oder das Sie nur ['include'] möchten (http://php.net/manual/en/function.include.php)) die Quelldatei, die diese Klasse einmal enthält? – Schlaus

Antwort

3

Sie können eine Context Klasse erstellen, die ein Container für Ihre Bereichsvariablen ist und Ihnen dabei hilft, Code in einen Kontext einzubinden (auszuführen). Es wird eine Singleton-Klasse sein (es wird nur eine Instanz erstellt).

Hier ist, wie es zu benutzen: Die Methode current() die aktuelle Instanz zurückgibt, dann können Sie Variablen in den Kontext exportieren, indem Sie die export() Methode verwendet, dauert es eine Schlüssel/Wert-Array. Das Verfahren execute() einen Dateinamen als Parameter übernimmt und schließt sie mit den exportierten Variablen verfügbar sind, können Sie temporäre Variablen als zweiten Parameter hinzu:

//Somewhere before execute(); 
oContext::current()->export([ 
    'variable1' => 'value1', 
    'instance' => $instance 
]); 

//Then anywhere in your file: 
oContext::current()->execute("toBeIncluded.php", [ 
    'tmp_variable' => 'tmp_value' 
]); 

//toBeIncluded.php 
echo $variable1; 
echo $instance->method1(); 
echo $tmp_variable; 

In Ihrem Fall:

Haupt Funktion:

function parsePage($sLanguageCode) { 
    $oTranslator = new translator($sLanguageCode); 
    $aTranslations = $oTranslator->translations('page'); 
    $oBuilderClass = new builder($aTranslations); 

    //export variables to your context 
    //Don't be aware of memroy usage objects are passed by reference 
    oContext::current()->export(compact('oBuilderClass')); 

    //... queries to get data and set pagedata and get the template file 
    $oPageData = $oPage->getData(); 
    $aTemplateTags = $oTemplate->getTags(); 
    foreach($aTemplateTags as $sTag) { 
      $oPageData->outputData($sTag); 
    } 

    //.... 
} 

Objekt:

class phpFragment { 
    private $sData; 

    function render() { 
     oContext::current()->execute($oElement->sData); 
    } 
} 

finden Sie unten der Klassendeklaration:

oContext.class.php

/** 
* Class oContext 
*/ 
class oContext { 

    /** 
    * The singleton instance 
    * @var oContext 
    */ 
    private static $instance = null; 

    /** 
    * the exported variables 
    * @var array 
    */ 
    private $variables = []; 

    /** 
    * Return the singleton or create one if does not exist 
    * 
    * @return oContext 
    */ 
    public static function current() { 
     if (!self::$instance) { 
      self::$instance = new self; 
     } 
     return self::$instance; 
    } 

    /** 
    * Export an array of key/value variables 
    * 
    * @param $variables 
    * @return $this 
    */ 
    public function export($variables) { 
     foreach ($variables as $key => $value) { 
      $this->variables[$key] = $value; 
     } 
     return $this; 
    } 

    /** 
    * Include and execute a file in this context 
    * 
    * @param $file 
    * @param array $variables temporary exports will not be added to the context (not available in the next call) 
    * @return $this 
    */ 
    public function execute($file, $variables = []) { 
     //Populate variables 
     foreach (array_merge($this->variables, $variables) as $key => $value) { 
      ${$key} = $value; 
     } 
     include $file; 
     return $this; 
    } 

} 

ich diese Hilfe hoffen, dass Sie Ihr Ziel erreichen.

Viel Glück.

+0

Vielen Dank für Ihre Idee, ich denke, es passt am besten zu meinem Design :) – Abayob

0

Wenn ich Ihr Problem richtig verstehe, dann möchten Sie einen vollständigen Code von PHP-Datei als eine Methode von Objekt aufgerufen werden. Wenn ja, dann möchten Sie wahrscheinlich eine eval Funktion verwenden, die here beschrieben wird.

Mit eval Funktion können Sie Ihre PHP-Datei als String lesen und es als PHP-Code bewerten, anstatt es aufzunehmen.

Wenn Ihre PHP-Datei eine return-Anweisung dann durch Dokumentation folgende verwenden

eval() gibt NULL zurück, es sei denn, Rückkehr in den ausgewerteten Code genannt wird, in diesem Fall wird der Wert zurückgegeben zurück geführt wird.

Sie können diesen Wert einfach von Ihrer Methode zurückgeben.

Wenn Ihre eingebundenen Dateien so einfach sind, wie Sie in Beispiel zeigen, dann diesen Effekt erzielen Sie diesen Teil des Codes

class phpFragment { 
    private $sData; 

    function render() { 
     return include $oElement->sData; 
    } 
} 

mit diesem

class phpFragment { 
    private $sData; 

    function render() { 
     //read a file into variable as string 
     $phpCode = file_get_contents($oElement->sData);     

     //prepare code by adding return statement and '?>' at the begining (because you have an open tag in php files). 
     $phpCode = '?> ' . str_replace('$oBuilderClass->build_element', 'return $oBuilderClass->build_element', $phpCode); 

     //I guess that included files don't use any variables declared out of file so we need to simply escape every '$' character in file 
     //that they can evaluate correctly. 
     $phpCode = str_replace('$', '\$', $phpCode); 

     return eval($phpCode); 
    } 
} 
+0

Vielen Dank für Ihre Lösung.Ich habe jedoch gelesen, dass eval() ist eine gefährliche Funktion und dies in meinem Kern-Code, scheint schlechtes Design, schlimmer als meine atm XD – Abayob

+0

Ja, Sie haben Recht, dass im Allgemeinen kann es gefährlich sein, aber wenn Sie erwarten Nur einfacher Code für die Objekterstellung und wenn Sie diesen Code mit einem Muster beschreiben (und mit diesem Muster validieren), können Sie das Risiko reduzieren. Der Vorteil der eval-Funktion ist, dass sie einen Wert aus dem ausgewerteten Code wie eine Funktion zurückgeben kann (aus diesem Grund habe ich meine Antwort vorgeschlagen). – zajonc

0

ersetzen müssen Klingt wie eine Abhängigkeit Injektionsproblem: Sie wollen $oBuilderClass in den Bereich innerhalb der include Code sein?

Wenn Sie Zugriff auf einen Anwendungsabhängigkeitscontainer haben, würde ich das Objekt mit diesem Container registrieren. In generischen Begriffen wie etwa \Application::bind('Builder', $oBuilderClass), dann später tun Builder::build_element. Dass Sie jedoch Ihren eigenen View-Renderer schreiben, deutet darauf hin, dass Sie keinen Zugang zu einer Framework-Einrichtung mit einem formellen IoC container haben.

Sie Gesetzt keine IoC-Container haben, die zweckmäßigste Art und Weise zu tun wäre:

$GLOBALS['oBuilderClass'] = new builder(...); 

dann später in Ihr gehören:

global $oBuilderClass; 
$oBuilderClass->build_element(...); 

Das ist nicht besonders elegant ist, aber . Sie könnten die Builder betrachten um vorbei, so dass am Ende des Anrufs gut Sie haben:

function render(builder $oBuilderClass) { 
    return include $oElement->sData; 
} 

, die zum Zeitpunkt des Includes $oBuilderClass in Rahmen setzt. Ich würde zuerst einen formellen IoC-Container bevorzugen, dann das Objekt herumreichen und dann, wenn nichts davon für Sie funktioniert, dann die globale Variable verwenden.

+0

Vielen Dank für Ihre Erklärung/Idee, aber ich möchte keine globale Variable verwenden, sein schlechter Code – Abayob

Verwandte Themen