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

Dan*_*Dan 2 php oop model-view-controller caching

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

构建页面的缓存是__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';
    }
}
Run Code Online (Sandbox Code Playgroud)

模型

class thread extends model{

    public function getTitle($threadId){

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

        return $data;
    }
}
Run Code Online (Sandbox Code Playgroud)

数据库

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

高速缓存

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();
    }

}
Run Code Online (Sandbox Code Playgroud)

视图

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

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

</body>
</html>
Run Code Online (Sandbox Code Playgroud)

ter*_*ško 8

"外包"缓存

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

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

要开始研究这个,你应该阅读 两篇文章.

你的目标是什么?

在开始尝试添加缓存之前,请确保您确实需要它.做一些基准测试,看看你的瓶颈是什么.为优化而优化是毫无意义的,通常也是有害的.

如果您知道(并且有数据备份它......并不是"感觉")您的应用程序正在进行太多的SQL查询,而不是跳转到查询缓存,那么您应该首先检查一下这些查询是什么.

例如:
如果您看到,您正在执行慢速查询每个页面视图只是为了生成标签云,您应该存储已完成的标签云(作为HTML片段)并仅在更改某些内容时更新它.

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

这不是MVC

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

  • "视图"不是模板
  • "model"不是数据库抽象
  • "controller"不是应用程序逻辑

您似乎也忽略了"图层"一词的含义.它不是"类"的同义词.图层是可重复使用的组件组,可在类似情况下重复使用[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
    
    Run Code Online (Sandbox Code Playgroud)
  • 如果将持久层扩展为使用简单映射器,则缓存的另一个点是存储库和/或标识映射.用一个简单的代码示例解释起来就太难了.相反,您应该阅读企业应用程序架构模式一书.

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

  • 请停止使用单例来建立数据库连接.它使得单元测试成为不可能并导致与类的特定名称的紧密耦合.我建议改为使用这种方法并在需要它的类中注入数据库连接.

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

    出现此问题主要是因为您的神奇数据库类.相反,您应该在多个数据映射器中分离持久性逻辑.这样你就不会面对所有查询都有单一方法的自身问题.

  • var关键字是PHP4的人工制品.现在我们用public,privateprotected.

  • 您正在编写代码中的连接详细信息.它基本上违反了OCP(这是一个愚蠢的版本:这里).

  • @ alpham8 ORM是反模式http://seldo.com/weblog/2011/08/11/orm_is_an_antipattern.至于MVC,您可以阅读:http://poincare.matf.bg.ac.rs/~andjelkaz/pzv/cas4/mvc.pdf (2认同)