【问题标题】:Getting my head around classes and scope of vars了解 vars 的类和范围
【发布时间】:2013-09-09 10:56:55
【问题描述】:

我正在重写我的很多旧的肮脏的意大利面条代码,目前正在尝试掌握类、函数并围绕 MVC 模型松散地重建我的网站。

但是,我无法让我的标题模板包含,以引用由我的主配置文件自动加载的用户帐户详细信息,我认为我错过了一个非常重要的步骤。

错误信息是Fatal error: call to member function is_loggedin() on a non-object...,所以我猜测在template.class.php 中执行的包含无法访问account.class.php 函数。

更新:在 header.tpl.php 中执行 var_dump(get_included_files()) 表明 account.class.php 和 template.class.php 都包含(按此顺序)。我还尝试在 header.tpl.php 的顶部手动包含 account.class.php 以查看它是否会产生任何影响......它没有。帮助:(

我还应该注意,我可以毫无问题地从 index.php 调用 $_account->is_loggedin()。 Jst 不在包含的文件 header.inc.php 中。

我可能会遇到这一切都错了,所以如果有人可以提供一些指示,下面是我的代码的简化编写:

index.php

<php require 'defaults.php'; ?>
<html>
<head>
...
</head>
<body>
<?php $_template->load('header'); ?>
....
</body>

defaults.php

session_start();

// define path settings
// connect to database, memcache
// lots of other stuff....

//autoloader for functions
spl_autoload_register(function ($class) {
  if (file_exists(CLASS_PATH.DS.$class.'.class.php'))
  {
    include CLASS_PATH.DS.$class.'.class.php';
  }
});

$_account = new account();  // autoload user account stuff
$_template = new template(); // autoload templates

account.class.php

class account
{
  private $db;

  public function __construct($db) {
    $this->db = $db;
  }


  public function is_loggedin() {
    // do various session checks
  }
}

template.class.php

class template
{
  public function load($template)
  {
    if (file_exists(TPL_PATH.DS.$template.'.tpl.php'))
    {
      include TPL_PATH.DS.$template.'.tpl.php';
    }
  }
}

header.tpl.php

<div id="header">
<?php if($_account->is_loggedin() == true): ?>
  <p>logged in</p>
<?php else: ?>
  <p>not logged in</p>
<?php endif; ?>

【问题讨论】:

  • 在使用该类之前,请执行var_dump(get_included_files()); 以查看您的类文件是否包含在内。您描述的错误通常来自不存在的类。要么您的自动加载器注册失败,要么包含类文件的某处存在错误。一步一步调试它,你应该离解决问题更近了一点。
  • 您的应用程序模型可以改进,您的代码风格有点像 PHP4 的老式风格,但是对于类、模式和模型的新手来说,这是一个良好的开端。作为提示,我会将 template.class.php 中的 if 子句扩展为 else { throw new Exception("include file not found"); } 之类的东西 - 以查看该文件是否真正包含在内。
  • 是的,不幸的是,我很老派,但我试图打破这个习惯。我已将异常添加到 defaults.php 中的 autoloaer 和 template.class.php,但我没有收到任何错误。该模板肯定包含在内,因为当我访问索引时,我看到了标题模板的内容....但除此之外我不确定
  • 我将从var_dumping $_account 开始,就在引发错误的行之前,这样您就可以准确地看到它认为变量是什么。

标签: php class autoloader


【解决方案1】:

您尝试访问的$_account 是您的template::load 方法的函数范围内的一个变量,您初始化的$_account 是一个全局变量。

如果您想使用全局变量,您应该在函数中使用global $_account 声明它或使用$GLOBALS['_account']

一个简单的模板示例(其余部分从您的源代码中复制):

Template.class.php

interface IApiHandler {
    public function printContent();
}

SomeTemplate.class.php

class SomeTemplate implements Template {
    public function printContent() {
        $account = Account::getCurrent();
        ?>
        <div id="header">
        <?php if($account->is_loggedin() == true): ?>
            <p>logged in</p>
        <?php else: ?>
            <p>not logged in</p>
        <?php endif;
    }
}

Account.class.php

class Account {
    private static $current = null;
    public static function getCurrent() {
        if(self::$current === null) {
            self::$current = new Account();
        }
        return self::$current;
    }
    public function __construct() {
        //account init...
    }
    public function isLoggedIn() {
        return rand()%2;
    }
}

defaults.php

session_start();

// define path settings
// connect to database, memcache
// lots of other stuff....

//autoloader for functions
spl_autoload_register(function ($class) {
  if (file_exists(CLASS_PATH.DS.$class.'.class.php'))
  {
    include CLASS_PATH.DS.$class.'.class.php';
  }
});

$headerTemplate = new HeaderTemplate();//not included in the example...
$bodyTemplate = new SomeTemplate();

index.php

<php require 'defaults.php'; ?>
<html>
<head>
...
</head>
<body>
<?php $headerTemplate->printContent(); ?>
<?php $bodyTemplate->printContent(); ?>
</body>

还应注意,这缺少 MVC 中的 C。这只是一个如何将模板制作为类的示例。

通常索引(或者在这种情况下为 default.php)只需要决定哪个控制器应该处理请求。然后控制器必须决定(或默认)应该使用哪个模板(如果有的话)。

如果所有的 html 都包含在模板中会更好,在控制器处理请求之前不应该打印输出。

【讨论】:

  • 是否正在使用全局“hack”来解决我在模型中引入的问题?如果是这样,有没有更好的方法来解决这个问题?
  • 一般来说,它与全局变量一样多。最好使用静态类变量而不是全局变量,它们仍然是全局的,但至少是按类组织的,IDE 可以更好地处理它们。如果您想完全避免使用全局变量,则必须将其作为参数传递到各处(哪个选项更好,这本身就是一个带有宗教辩论的完整主题)。
  • 只是稍微扩展一下:当您使用includerequire 时,就像您在template::load 中所做的那样,它直接将文件包含在适当的位置,在这种情况下意味着它是load 函数体的一部分。这可能不是你真正想要的,它也可能会以其他(类似)方式咬你。例如,如果您在包含的文件中定义任何类的函数,它们也将没有函数之外的范围。不过,我不确定解决方案是什么,即如何包含变量文件。不过,这似乎应该很常见。
  • 解决混淆的一个简单方法是将模板定义为类(具有通用的基类或接口)并通过自动加载器包含它们。这样一来,范围混淆就会减少,您的 IDE 也将能够正确确定变量范围。
  • 感谢 Vatev 的所有帮助。我想我明白你在说什么,但我无法完全理解它。如果你有机会,我真的很感激一个例子。
猜你喜欢
  • 2021-02-03
  • 1970-01-01
  • 2016-04-23
  • 2011-04-15
  • 2015-10-03
  • 1970-01-01
  • 2011-09-10
  • 2015-10-03
相关资源
最近更新 更多