Search code examples
phpoopscoping

How to run code from included filepath of object into function scope outside object?


I am currently refactoring code from a page parser function to OOP. I am having difficulties including and running code from a file into main function scope:

Object:

class phpFragment {
    private $sData;

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

Object container class:

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;
        }
    }
}

Main function:

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 of include (example):

<?php

$oBuilderClass->build_element(.... parameters here);

?>

I want to initiate the builder-class only once, because it contains quite some data and I don't want to recreate that on every include.

How can I return the code of the include into the parsePage function where the builderClass can be used?


Solution

  • You can create a Context class that will be a container of your scope variables and helps you include (execute) code inside a context. It will be a singleton class (only one instance will be created).

    Here is how to use it: The method current() returns the current instance then you can export variables to the context by using the export() method, it takes a key/value array. The method execute() takes a file name as a parameter and includes it with the exported variables available, you can add temporary variables as a second parameter:

    //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 your case:

    Main function:

    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);
        }
    
        //....   
    }
    

    Object:

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

    You find bellow the class declaration:

    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;
        }
    
    }
    

    I hope this help you achieve your aim.

    Good Luck.