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

时间:2013-05-04 14:07:53

标签: php html oop object templating

所以我一直在研究模板引擎以及如何创建自己的简单模板引擎。从纯粹的学习角度来看,我通过其中几个来阅读here

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

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

易混吗

也许以下代码会有所帮助。

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

$_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实例设置为全局时,一切正常。但这是一种正确的方法吗?

5 个答案:

答案 0 :(得分:3)

关于对象继承

类是对象的模板,它定义了对象属性和方法,而object是类的实例。扩展类时,子类从父级继承属性和方法。

在您的情况下,没有继承(父子关系),$_header作为单独的对象只是$_page的属性。要在这两个对象之间启用“通信”,$_header必须引用$_page对象。


模板类

这是您正在使用的Template类的修改版本。动态创建属性时,应使用__set()__get() magic methods。它还使用__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'对象中的变量的一种方法是通过构造函数将父属性添加到模板类:

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;

将父级属性设为本地

另一种方法是让它们成为本地的(如果你不想打扰$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;
}

其他信息

Adapter Design Pattern

PHP Overloading

Magic Methods

Smarty Template Engine - variable scopes

答案 1 :(得分:1)

问题是$ _header不是{_ 3}的$ _page的子项,你不希望它们是真正的php父母和孩子。

相反,更改tplEngineChild构造函数以将$ parent作为附加参数,在本例中为$ _page。

构造函数可能如下所示:

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

    if (isset($template))
    {
        $this->load($template);
    }
}

现在$ 标头可以使用$ this-&gt; parent-&gt; username。确保在父类定义中使用“public $ username”。您可以使用php class inheritance _get)自动解析父级的属性(如果子级中不存在)。

你也可以传递$ _header而不是$ _header-&gt; publish();到$ _page-&gt;设置并将$ _page模板更改为header-&gt; publish()?&gt;。这样,标题会在$ _page执行时发布,而不是在调用$ _page-&gt; set()时发布。

答案 2 :(得分:1)

某些概念以不同的方式用于不同的语言。尽管使用了相同的词,但它们并不相同。这可能很混乱。这是我认为是您问题的来源。我将描述模板中使用的三种模式。每种模式都有父母与子女之间的特定关系。

1。区分实施

模板设计模式具有严格的父子关系。子节点是父节点的扩展,通常是一个抽象类。每个孩子都是父母的不同实现。抽象模板类的示例例如是Shape。子实现可以是Triangle,Square和Circle。 它们都共享一些公共抽象方法,如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片段中使用的是相同的数据(当前请求和会话的所有数据)。它们共享相同的数据,但它们不应该相互继承。他们也不共享任何实现功能。您可以使用一个内容块,使用寻呼机显示搜索结果的概述。或者你可以有一个带有静态页脚的块。在每个html模板中,只有一个标题和一个正文。然而,可以有更多的菜单和特定的菜单可以在不同的地方以不同的形状出现。因此,您应该考虑观察者或MVC模式。使用的数据是模型部分。在一个请求期间,对于数据的所有视图都是相同的。每个块都是模型的不同视图,并将使用它所需的信息。没有块需要知道任何其他块的状态或数据。在我看来,这就是为什么你问$ _page应该是全局的?由于共享数据,您需要它。不是因为文件的html部分。 (这是一个组合问题。)但是,如果您将root.php的这两个部分分开并为所有块创建一个公共数据对象,那么它可以在$ _page不是全局的情况下工作。

结论:

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

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

答案 3 :(得分:0)

另一种可能的方法是不区分tplEngine和tplEngineChild。这是我的意思的简单实现。

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");

希望这有帮助

答案 4 :(得分:0)

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

所有那些着名系统实际使用的模板系统(称之为tpl,magento,oscommerce和列表很长)都不是模板。

我为什么这样说:

模板应该是(您命名语言,HTML,XML,WAP,CSS,JS等)自然代码的一部分,并将参数替换为它们。

模板不应包含编程语言,原因如下: - 图形设计师或HTML播放器通常不会理解代码 - 您需要程序员来修改模板 - 模板只是另一段PHP代码 - 您(通常)需要掌握编程语言的大量知识才能修改和维护代码。

模板应该是一种自然语言代码,其编程技巧人员可以轻松理解参数

这是一个很好的模板系统,如Java模板,C模板和其他语言模板,因为它不会将PHP与本机代码混合:

http://www.webability.info/?P=documentacion&wiki=/DomCore/reference/Templates

只需2美分即可获得更好的编程