代码之家  ›  专栏  ›  技术社区  ›  ryeguy

模板化系统范围问题

  •  3
  • ryeguy  · 技术社区  · 15 年前

    我正在尝试用PHP开发一个框架视图系统,但我不知道如何让嵌入的视图接收其父级的变量。例如:

    视图类

    class View
    {
        private $_vars=array();
        private $_file;
    
        public function __construct($file)
        {
            $this->_file='views/'.$file.'.php';
        }
    
        public function set($var, $value=null)
        {
            if (is_array($var))
            {
                $this->_vars=array_merge($var, $this->_vars);
            }
            else
                $this->_vars[$var]=$value;
    
            return $this;
        }
    
        public function output()
        {
            if (count($this->_vars))
                extract($this->_vars,  EXTR_REFS);
            require($this->_file);
            exit;
        }
    
        public static function factory($file)
        {
            return new self($file);
        }
    }
    

    test.php(顶层视图)

    <html>
        <body>
            Hey <?=$name?>! This is <?=$adj?>!
            <?=View::factory('embed')->output()?>
        </body>
    </html>
    

    embed.php(嵌入test.php中)

    <html>
        <body>
            Hey <?=$name?>! This is an embedded view file!!
        </body>
    </html>
    

    代码:

    $vars=array(
        'name' => 'ryan',
        'adj' => 'cool'
    );
    View::factory('test')->set($vars)->output();
    

    输出:

    Hey ryan! This is cool! Hey [error for $name not being defined] 
    this is an embedded view file!!
    

    问题是我在顶层视图中设置的变量不会传递到嵌入视图。我怎么能做到?

    4 回复  |  直到 12 年前
        1
  •  1
  •   Sean Clark Hess    15 年前

    所以,我不完全回答你的问题,但这里是我的超简单的手工制作的模板系统。它支持您正在尝试做的事情,尽管接口是不同的。

    // Usage
    $main = new SimpleTemplate("templating/html.php");
    $main->extract($someObject);
    $main->extract($someArray);
    $main->name = "my name";
    $subTemplate = new SimpleTemplate("templating/another.php");
    $subTemplate->parent($main);
    $main->placeholderForAnotherTemplate = $subTemplate->run();
    echo $main; // or $main->run(); 
    
    // html.php
    <html><body><h1>Title <?= $name ?></h1><p><?= $placeHolderForAnotherTemplate ?></p></body></html>
    
        <?php
    // SimpleTemplate.php
    function object_to_array($object)
    {
        $array = array();
        foreach($object as $property => $value)
        {
            $array[$property] = $value;
        }
    
        return $array;
    }
    
    class SimpleTemplate
    {
        public $source;
        public $path;
        public $result;
        public $parent;
    
        public function SimpleTemplate($path=false, $source=false)
        {
            $this->source = array();
            $this->extract($source);
            $this->path($path);
        }
    
        public function __toString()
        {
            return $this->run();
        }
    
        public function extract($source)
        {
            if ($source)
            {
                foreach ($source as $property => $value)
                {
                    $this->source[$property] = $value;
                }
            }
        }
    
        public function parent($parent)
        {
            $this->parent = $parent;
        }
    
        public function path($path)
        {
            $this->path = $path;
        }
    
        public function __set($name, $value)
        {
            $this->source[$name] = $value;
        }
    
        public function __get($name)
        {
            return isset($this->source[$name]) ? $this->source[$name] : "";
        }
    
        public function mergeSource()
        {
            if (isset($this->parent))
                return array_merge($this->parent->mergeSource(), $this->source);
            else
                return $this->source;
        }
    
        public function run()
        {
            ob_start();
            extract ($this->mergeSource());
            include $this->path;
            $this->result = ob_get_contents();
            ob_end_clean();
            return $this->result;
        }
    }
    
        2
  •  0
  •   smoove    15 年前

    好吧,您创建了一个新的类实例,所以在嵌入的模板中没有定义变量。您应该尝试复制对象,而不是创建新对象。

    编辑:我说的是工厂方法

        3
  •  0
  •   zombat    15 年前

    主要的问题是你的观点彼此之间没有直接的了解。通过调用:

    <?=View::factory('embed')->output()?>
    

    在您的“父”视图中,您创建并输出一个不知道它在另一个模板中的事实的模板。

    这里我可以推荐两种方法。

    #1-关联模板。

    通过使嵌入的模板成为父模板的“子模板”,可以允许它们访问父模板的变量 output() 时间。我在构建的视图系统中使用这种方法。就像这样:

    $pView = new View_Parent_Class();
    $cView = new View_Child_Class();
    $pView->addView($cView);
    

    AT $pview->render() 时间,子视图可以很容易地访问父视图的变量。

    这个方法可能需要对您进行大量的重构,所以我将不考虑脏的细节,继续第二种方法。

    #2-传递父变量

    考虑到目前为止所采用的方法,这可能是最容易实现的方法。向输出方法中添加一个可选参数,然后稍微重写它,如下所示:

    public function output($extra_vars = null)
    {
        if (count($this->_vars))
            extract($this->_vars,  EXTR_REFS);
        if (is_array($extra_vars)) extract($extra_vars, EXTR_REFS);
        require($this->_file);
        exit;
    }
    

    如果还添加了一个简单的getter方法:

    public function get_vars()
    {
        return $this->_vars;
    }
    

    然后,您可以使用对父级变量的有效读取权限嵌入文件:

    <?=View::factory('embed')->output($this->get_vars())?>
    

    $this 将是对当前模板的引用,即父模板。请注意,通过此方法可以发生变量名冲突,因为 extract 电话。

        4
  •  0
  •   Mario    15 年前

    您可以使您的$撘vars属性保持静态,不是特别优雅,但可以实现您正在尝试实现的目标。

    旁注…set()函数中的数组_merge()是错误的,请交换两个变量。