2

下面的代码是否显示了一种可接受的方式来缓存完全构建的页面和数据库查询?

已构建页面的缓存从__construct控制器中的 开始,然后以 结束__destruct,在此示例中,所有页面默认缓存 15 分钟到一个文件。

查询缓存已完成,apc它们在每个查询的指定时间内存储在内存中。在实际站点中,apc 缓存还有另一个类,以便可以根据需要进行更改。

我的目标是构建最简单的 mvc,我失败了还是走在正确的轨道上?

控制器

//config
//autoloader
//initialiser - 

class controller {

    var $cacheUrl;

    function __construct(){

        $cacheBuiltPage = new cache();
        $this->cacheUrl = $cacheBuiltPage->startFullCache();
    }

    function __destruct(){

        $cacheBuiltPage = new cache();
        $cacheBuiltPage->endFullCache($this->cacheUrl);
    }
}

class forumcontroller extends controller{

    function buildForumThread(){

        $threadOb = new thread();
        $threadTitle = $threadOb->getTitle($data['id']);

        require 'thread.php';
    }
}

模型

class thread extends model{

    public function getTitle($threadId){

        $core = Connect::getInstance();
        $data = $core->dbh->selectQuery("SELECT title FROM table WHERE id = 1");

        return $data;
    }
}

数据库

class database {

    public $dbh;
    private static $dsn  = "mysql:host=localhost;dbname=";
    private static $user = "";
    private static $pass = '';  
    private static $instance;

    private function __construct () {
        $this->dbh = new PDO(self::$dsn, self::$user, self::$pass);
    }

    public static function getInstance(){
        if(!isset(self::$instance)){
            $object =  __CLASS__;   
            self::$instance = new $object;
        }
        return self::$instance;
    }

    public function selectQuery($sql, $time = 0) {

        $key = md5('query'.$sql);

        if(($data = apc_fetch($key)) === false) {

            $stmt = $this->dbh->query($sql);
            $data = $stmt->fetchAll();

            apc_store($key, $data, $time);
        }
        return $data;
    }
}

缓存

class cache{

    var url;

    public function startFullCache(){

        $this->url = 'cache/'.md5($_SERVER['PHP_SELF'].$_SERVER['QUERY_STRING']);   

        if((@filesize($this->url) > 1) && (time() - filectime($this->url)) < (60 * 15)){
            readfile($this->url);
            exit;
        }

        ob_start();

        return $this->url;
    }

    public function endFullCache($cacheUrl){

        $output = ob_get_contents();
        ob_end_clean();

        $output = sanitize_output($output);

        file_put_contents($cacheUrl, $output);

        echo $output;
        flush();
    }

}

看法

<html>
<head>
<title><?=$threadTitle[0]?> Thread - Website</title>
</head>
<body>

    <h1><?=$threadTitle[0]?> Thread</h1>

</body>
</html>
4

4 回答 4

8

“外包”缓存

首先,您必须了解GET请求的缓存通常在整个互联网上完成。特别是如果您的用户通过某种代理进行连接。

然后还可以设置较长的过期时间,以便用户的浏览器缓存 HTML 页面和/或媒体文件。

要开始研究这一点,您应该阅读 两篇文章。

你的目标是什么?

在开始尝试添加缓存之前,请确保您确实需要它。做一些基准测试,看看你的瓶颈是什么。为了优化而优化是没有意义的,而且往往是有害的。

如果您知道(并且有数据支持它......这与“感觉”无关)您的应用程序正在执行过多的 SQL 查询,而不是跳转到查询缓存,您应该首先检查这些查询的用途。

例如:
如果您看到,您对每个页面视图执行慢查询只是为了生成标签云,那么您应该存储已经完成的标签云(作为 HTML 片段)并仅在发生更改时更新它。

此外,在尝试提高性能时, “添加缓存”绝不应该是您的第一步。如果您的查询很慢,请使用EXPLAIN以查看它们是否正确使用索引。确保您没有多次查询相同的数据。还要看看,如果查询真的有意义。

这不是 MVC

我不确定,你是从哪里学会这样写的,但你似乎错过了 MVC 的全部要点:

  • “视图”不是模板
  • “模型”不是数据库抽象
  • “控制器”不是应用程序逻辑

您似乎也缺少“层”一词的含义。它不是“类”的同义词。层是在类似情况下可重用的可重用组件组[1]

您可能会从阅读这篇文章和这篇文章中受益。它们应该可以帮助您了解这种架构模式的基础知识。

在 MVC 架构中缓存在哪里?

在使用 MVC(或受 MVC 启发的)架构时,基本上有两点可以进行缓存:视图和持久性逻辑。

缓存视图主要需要重用一次渲染的模板(MVC 中的每个视图都将处理多个模板和相关的 UI 逻辑)。请参阅前面带有标签云的示例。

持久性逻辑中的缓存将取决于您的实现。

  • 您可以使用服务缓存应该传递给域对象的数据:

    注意:在实际应用中,new实例不会在这里。相反,您将使用一些工厂

    $user = new User;
    $user->setId( 42 );
    
    $cache = new Cache;
    
    if ( !$cache->fetch( $user ))
    {
        $mapper = new UserMappper;
        $mapper->fetch( $user );
    }
    
    $user->setStatus( User::STATUS_BANNED );
    $cache->store( $user );
    $mapper->store( $user );
    
    // User instance has been populated with data
    
  • 缓存的另一点是存储库和/或身份映射,如果您将持久层扩展到使用简单映射器之外。用一个简单的代码示例很难解释。相反,您应该阅读《企业应用程序架构模式》一书。

..您的代码中的其他一些不良做法:

  • 请停止使用单例建立数据库连接。无法编写单元测试并导致与类的特定名称紧密耦合。我建议改用这种方法并将数据库连接注入需要它的类中。

  • 此外,如果您的查询没有参数,则准备它没有意义。准备好的语句用于将数据传递给 SQL .. 但您的示例都没有任何参数。

    这个问题主要是因为你神奇的数据库类。相反,您应该在多个数据映射器中分离持久性逻辑。这样,您就不会面临为所有查询使用单一方法的自我造成的问题。

  • var关键字是 PHP4 的神器。现在我们使用public,privateprotected

  • 您正在对代码中的连接详细信息进行硬编码。这基本上违反了OCP(简化版:here)。

于 2014-01-15T09:46:44.063 回答
3

更新

这是在 PHP mvc 中缓存查询和构建页面的可接受方式吗?

已构建页面的缓存从控制器中的 __construct 开始,然后以 __destruct 结束,在此示例中,所有页面都默认缓存 15 分钟到文件中。

当释放所有引用或脚本终止时,将调用析构函数。我认为这意味着脚本正确终止时。我会说关键异常不能保证调用析构函数。

例如

 class A 
 {
    public function __construct()
    {
       echo "Construct\n";
    }

    public function __destruct()
    {
      echo "Destruct\n";
    }
 }

测试代码:

   $test = new A();
    die( "Dead\n");  // Will output Construct; dead; Destruct

   $test = new A();
   throw new Exception("Blah\n"); // Construct, Fatal error (no destruct)

   $test = new A();
   require_once( 'invalid_file.php'); // Construct, Fatal error (no destruct)

你最好使用register_shutdown_function()来确定。但小心点

可以对 register_shutdown_function() 进行多次调用,每次调用的顺序与注册时的顺序相同。如果您在一个已注册的关闭函数中调用 exit(),则处理将完全停止,并且不会调用其他已注册的关闭函数。”如果其他关闭函数在您之前运行,则无法保证您的关闭函数会被调用。

恕我直言,您正在重新发明轮子,已经有很多框架了。你想要一个简单又小的吗?好吧,有Silex

它是由创建 Symfony 的同一个人构建的。相信我,你会浪费你的时间。

或者为什么不尝试使用Laravel你可以只选择你想要的包而不是所有框架他们已经有一个设计良好的缓存系统见http://laravel.com/docs/cache

要了解如何以 MVC 风格正确完成缓存,Symfony 2 的文档有一个很好的解释

另请阅读此问题Caching strategy in MVC Framework

就其中任何一项的必要性而言;这真的取决于你的情况。以我的经验,除非您期望有大量用户(例如,同时在您的网站上有几十个用户),否则您不需要缓存。另一方面,如果没有经过深思熟虑的缓存策略,像 StackOverflow 这样的网站将无法运行。


How would you create a build function to cache the entire built page?

正如我从您的问题中了解到的那样,您想缓存整个页面?

How would you create a build function to cache the entire built page?

您可以简单地使用输出缓冲来实现这一点。

一个例子是你有index.php代码:

<?php

 ob_start();   

 // All your mvc and application logic here

 $output = ob_get_contents();
 ob_end_clean();

现在在$output中捕获 ob_start() 和 ob_get_contents() 之间的整个页面输出

您可以将其保存在文件中并做任何您想做的事情

您可以在 PHP 网站中阅读有关ob_get_contents()的更多信息

于 2014-01-15T00:47:43.743 回答
2

这完全取决于您的性能问题所在。如果它们在您的数据库查询中,则缓存它们 - 但当然您的控制器需要为脏数据做好准备。

如果您要在控制器层缓存内容,那么效果会更好,但您可能需要缓存更多内容(您的数据库数据将小于您的 HTML)。当然,用户需要为看到脏数据做好准备。

不幸的是,您并没有真正的硬性规则,因为每个解决方案都有不同的要求。我的建议是仅在您真正需要时才开始缓存数据。仔细查看您的性能瓶颈在哪里并适当地进行缓存,并确保您可以向外扩展(更多机器)而不仅仅是向上扩展(增加机器规格)。

于 2013-02-21T22:33:30.180 回答
1

我添加了 CodingInsane 发布的内容!

他是对的,这样你就可以轻松制作自己的小缓存机制。

只需将 $output 的内容(在 CodingInsane 帖子中)写入文件,如:the_file.php.cache 并下次在 the_file.php 中读取 the_file.php.cache 的内容并将其显示给用户并退出。

然而,任何缓存机制都需要一种更新方式(重建页面)。为此,您只需跟踪内容是否已更改或检查内容上次更改的时间并将其与上次修改 the_file.php.cache 的时间(filemtime())进行比较。

祝你好运!

于 2014-01-15T01:21:08.003 回答