在php的子对象范围内访问父对象变量


Accessing parent object variables from within the scope of the child object in php

所以我一直在研究模板引擎以及如何创建我自己的简单模板引擎。从纯粹的学习角度来看,我通读了其中的几篇,比如下面这篇。

使用上面链接中提到的类的一个小修改版本,我想测试一下,但遇到了一个问题。

当调用内部HTML的相同模板类的实例,然后将其作为var/value对赋值给父实例时,我无法访问HTML(子对象)内的主父变量。

困惑吗?

也许下面的代码会有帮助。

因此,如果我实例化模板如下(模板类与上面链接中提到的相同)-

$_page = new tplEngine();
$_page->load(TPLFILES_DIR . "/root.php");

,然后实例化header.html作为tplEngine类的新实例,并赋值它作为第一个实例的变量,如下所示-

$_header = new tplEngineChild(TPLFILES_DIR . "/common/header.html");
$_page->set("header", $_header->parse());

的地方……

root.php
---------------

<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
        <meta http-equiv="X-UA-Compatible" content="IE=Edge" />
        <title><?php print $this->title; ?></title>
        <meta name="keywords" content="<?php print $this->meta_keywords; ?>" />
    <meta name="description" content="<?php print $this->meta_description; ?>" />
        <?php foreach($this->styles as $stylepath) : ?>
        <link rel="stylesheet" type="text/css" href="<?php print $stylepath; ?>" />
        <?php endforeach; ?>
    </head>
    <body>
        <div class="body-wrap">
            <div class="header">
                <?php print $this->header; ?>
            </div>
            <div class="content-wrap">
                <?php var_dump($this->mid_content); ?>
            </div>
            <div class="footer">
                <?php print $this->footer; ?>
            </div>
        </div>
    </body>
</html>

header.html
-----------------

<div class="mainHeader">
    <div class="logo">
        webTrack.in'
    </div>
    <div class="dashboard">
        <?php if($this->get(isLoggedIn) == false) : ?>
        <p class="greeting">Hello <span class="username"><?php echo this->username; ?></span></p>
        <a class="logout">logout</a>
        <?php else : ?>
        <p class="greeting">Hello <span class="username"><?php echo $this->username; ?></span></p>
        <p><a onclick="showLogin()">Login</a></p>
        <form id="loginForm" class="login form" action="" method="post">
            <input type="text" name="username" value="Username" />
            <input type="password" name="password" value="Password" />
        </form>
        <?php endif; ?>
    </div>
</div>
<nav>
    <ul class="headerNav">
        <li><a href="/">Home</a></li>
        <li><a href="/pricing">Plans and Pricing</a></li>
        <li><a href="/aboutUs">About Us</a></li>
    </ul>
</nav>

(在上面的例子中,$this->get(isLoggedIn)this->username是分配给$_page实例的变量)我遇到了一个问题,在header.html文件中,我无法访问tplEngine类的$_page实例下设置的变量。

解决这个问题的最好方法是什么?

当我在header.html中将$_page实例设置为全局时,一切工作正常。但这是一个正确的方法吗?

关于对象继承

类是对象的模板,定义对象的属性和方法,而对象是类的实例。当你扩展一个类时,子类继承父类的属性和方法。

在你的例子中,没有继承(父子关系),$_header作为一个单独的对象只是$_page的属性。为了使这两个对象之间能够"通信",$_header必须有一个对$_page对象的引用。


模板类

这是您正在使用的Template类的修改版本。当动态创建属性时,应该使用__set()__get()魔术方法。它还使用__toString()方法,以便模板对象可以被视为字符串。模板文件使用的所有变量都应该赋值给模板对象。通过使用这样定义的类,所有模板将同时呈现。

class tplEngine {
    private $template = '';
    public function __set( $var, $content )
    {
        $this->$var = $content;
    }
    public function __get( $var )
    {
        return ( isset($this->$var) ? $this->$var : null );
    }
    public function __construct( $template )
    {
        // is_readable() - tells whether a file exists and is readable
        if ( !is_readable( $template ) ) throw new IOException( "Could not find or access file: $template" );
        $this->template = $template;
    }
    public function __toString() 
    {
        ob_start();
        require ( $this->template );
        $content = ob_get_clean();
        return $content;
    }
}
// usage:
$_page = new tplEngine( TPLFILES_DIR . "/root.php" );
$_header = new tplEngine( TPLFILES_DIR . "/common/header.html" );
$_header->isLoggedIn = true;
$_header->username = 'some-username';
$_page->header = $_header;
// in root.php 
echo $this->header;

访问父变量

父属性

访问'parent'对象中的变量的一种方法是通过构造函数将parent属性添加到模板类中:

public function __construct( $template, $parent = null )
{
    // is_readable() - tells whether a file exists and is readable
    if ( !is_readable( $template ) ) throw new IOException( "Could not find or access file: $template" );
    $this->template = $template;
    $this->_parent = $parent;
}   

访问模板中的父属性,如:

$this->_parent->username;

设置父属性为local

另一种方法是使它们成为本地的(如果你不想为$this->_parent调用而烦恼的话,这是一个巧妙的技巧):

public function __toString() 
{
    ob_start();
    if ( $this->_parent ) {
        foreach ( get_object_vars( $this->_parent ) as $key => $value ) $$key = $value;
    }
    require ( $this->template );
    $content = ob_get_clean();
    return $content;
}

附加信息

适配器设计模式

PHP重载

神奇的方法

Smarty模板引擎-变量作用域

问题是$_header在php类继承中不是$_page的子节点,你不希望它们是真正的php父节点和子节点。

,将tplengineecchild构造函数改为接受$parent作为附加参数,在本例中为$_page。

构造函数可以像这样:

function __construct($parent = null, $template = null)
{
    if(isset($parent))
    {
        $this->parent = $parent;
    }
    if (isset($template))
    {
        $this->load($template);
    }
}

now $header可以使用$this->parent->username。确保在父类定义中有"public $username"。你可以使用php方法重载(_get)来自动解析父元素的属性,如果它不存在于子元素中。

也可以传递$_header而不是$_header->publish();$_page->设置并更改$_page模板为header->publish() ?>。这样,头信息在$_page发布时发布,而不是在调用$_page->set()时发布。

一些概念在不同的语言中以不同的方式使用。虽然使用了相同的单词,但它们并不相同。这可能会让人很困惑。我认为这就是你问题的根源。我将描述模板中使用的三种模式。每个模式在父模式和子模式之间都有其特定的关系。

1。区分实现

模板设计模式具有严格的父子关系。子类是父类的扩展,父类通常是一个抽象类。每个子节点都是父节点的不同实现。抽象模板类的一个例子是Shape。子实现可以是三角形、正方形和圆形。它们都共享一些公共抽象方法,如draw()和resize(),它们都具有相同的实现。抽象方法的目的是确保它们都有一个唯一的、有特色的方法实现(对于子方法)。基类也可以有一些非抽象方法。例如fill()和rotate()等方法。允许每个子节点重写这些方法,但如果默认实现足够,则不需要这样做。子进程将能够使用父进程的公共/受保护的数据和方法,参见http://en.wikipedia.org/wiki/Template_method_pattern。

2。可重复的作文

html文件中的模板系统服务于类似的概念,但目的不同。html文件中的模板系统的目的是创建一个灵活的独立块插入系统。每个区块都独立于任何其他区块,因此您不能假设它们有任何共同之处。他们可能有,但这不是强制性的。您可以将其与抽象类的共享方法进行比较,因为在每个html文件中,您都必须以与在其他文件中相同的方式实现它。它们是独立的块,以确保设计的最大灵活性。相同的内容块可以在不同的模板文件中使用而没有任何问题。它们应该能够这样运作。这就是复合设计模式。亲子关系最好描述为部分-整体关系,参见http://en.wikipedia.org/wiki/Composite_pattern。

3。共享数据,独特呈现

在每个html-fragment中使用相同的数据(当前请求和会话的所有数据)。它们共享相同的数据,但是它们不应该相互继承任何东西。它们也不共享任何实现特性。您可以有一个内容块,在其中使用分页器显示搜索结果的概述。或者你可以有一个带有静态页脚的块。在每个html模板中只有一个标题和一个正文。然而,可以有更多的菜单,一个特定的菜单可以在不同的地方以不同的形状出现。因此,您应该考虑使用Observer或MVC模式。使用的数据是Model部分。在一个请求期间对数据的所有视图都是相同的。每个块都是模型上的不同视图,并将使用它所需的信息。没有块需要知道任何其他块的状态或数据。在我看来,这就是为什么你问$_page是否应该是全局的原因。你需要它,因为共享数据。不是因为文件的html部分。(这是一个构图问题。)但是,如果您将root.php的这两个部分分开,并且为所有块提供一个公共数据对象,那么它可以在没有全局变量$_page的情况下工作。

结论:

模板设计模式中的父子关系是在类之间(而不是对象之间),html片段块之间的html文件是部分-整体关系,共享数据和任何特定html片段所需数据之间的模型-视图关系。类之间的父子关系是固定的,html片段之间的部分-整体关系是灵活的,模型-视图关系是标准化的,但不是固定的。

如果数据对象只创建一次,并且在请求期间保持不变,则效率最高。全局变量可以做到这一点,但是方法中的局部变量也可以做到这一点,就像类的静态变量一样。我建议您使用最适合应用程序维护的实现。

另一种可能的方法是不区分tplEngine和tplengineechild。下面是我的意思的一个简单实现。

class tmplEngine {
    protected $template_root = "";
    // container for the template variables
    protected $tmpl_vars = array();
    public function __construct($tmpl_dir = null){
         if ($tmpl_dir) $this->setTemplateDir($dir);
    }
    // sets a template root directory
    public function setTemplateDir($dir){
        $this->template_root = $dir;
    }
    // parses an external file from the current scope
    public function parse($file){
        ob_start();
            require($this->template_root.$file);
        return ob_get_clean();
    }
    // magic getter allows access as $tmplEninge->propertyName;
    public function __get($property){
        return array_key_exists($property, $tmpl_vars)?$this->tmpl_vars[$property]:"";    
    }
    // magic setter allow access as $tmplEngine->propertyName = "myVal"
    public function __set($property, $value){
        $this->tmpl_vars[$property] = $value;
    }
}

那么现在你的调用应该是这样的

$t = new tmplEngine(TPLFILES_DIR);
$t->header = $t->parse("/common/header.html");
$t->main = $t->parse("/common/article.html");
$t->footer = $t->parse("/common/footer.html");
echo $t->parse("/root.html");

希望能有所帮助

只是指出一些关于模板系统的有趣之处。根据我自己的经验,模板应该是....它们的意思是模板。不是一堆PHP代码。

所有那些著名的系统(比如tpl、magento、oscommerce等)所使用的模板系统都不是模板。

我为什么这么说:

模板应该是一段(你命名的语言,HTML, XML, WAP, CSS, JS等)自然代码,其中包含可以替换的参数。

模板不应该包含编程语言,为什么:-图形设计师或HTML玩家通常不理解代码-你需要一个程序员来修改模板模板变成了另一段PHP代码-你需要(通常)编程语言的大知识,能够修改和维护你的代码。

模板应该是一种自然语言代码,其参数对于低编程技能的人来说很容易理解

这是一个很好的模板系统,就像Java模板、C模板和其他语言模板一样,因为它没有将PHP与本地代码混合:

http://www.webability.info/?P=documentacion&维基=/DomCore/引用/模板

只是我的两分钱一个更好的编程