搜索
首页后端开发php教程使用php搭建自己的mvc框架

使用php搭建自己的mvc框架

Nov 26, 2016 pm 04:42 PM
mvcphp

一、什么是MVC

MVC模式(Model-View-Controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)。

MVC模式的目的是实现一种动态的程序设计,使后续对程序的修改和扩展简化,并且使程序某一部分的重复利用成为可能。除此之外,此模式通过对复杂度的简化,使程序结构更加直观。软件系统通过对自身基本部份分离的同时也赋予了各个基本部分应有的功能。专业人员可以通过自身的专长分组:

(控制器Controller)- 负责转发请求,对请求进行处理。

(视图View) – 界面设计人员进行图形界面设计。

(模型Model) – 程序员编写程序应有的功能(实现算法等等)、数据库专家进行数据管理和数据库设计(可以实现具体的功能)。

2209.jpg

模型(Model) “数据模型”(Model)用于封装与应用程序的业务逻辑相关的数据以及对数据的处理方法。“模型”有对数据直接访问的权力,例如对数据库的访问。“模型”不依赖“视图”和“控制器”,也就是说,模型不关心它会被如何显示或是如何被操作。但是模型中数据的变化一般会通过一种刷新机制被公布。为了实现这种机制,那些用于监视此模型的视图必须事先在此模型上注册,从而,视图可以了解在数据模型上发生的改变。

视图(View) 视图层能够实现数据有目的的显示(理论上,这不是必需的)。在视图中一般没有程序上的逻辑。为了实现视图上的刷新功能,视图需要访问它监视的数据模型(Model),因此应该事先在被它监视的数据那里注册。

控制器(Controller) 控制器起到不同层面间的组织作用,用于控制应用程序的流程。它处理事件并作出响应。“事件”包括用户的行为和数据模型上的改变。

二、为什么要自己开发MVC框架

网络上有大量优秀的MVC框架可供使用,本教程并不是为了开发一个全面的、终极的MVC框架解决方案,而是将它看作是一个很好的从内部学习PHP的机会,在此过程中,你将学习面向对象编程和设计模式,并学习到开放中的一些注意事项。

更重要的是,你可以完全控制你的框架,并将你的想法融入到你开发的框架中。虽然不一定是做好的,但是你可以按照你的方式去开发功能和模块。

三、开始开发自己的MVC框架

在开始开发前,让我们先来把项目建立好,假设我们建立的项目为todo,那么接下来的第一步就是把目录结构先设置好。

2210.jpg

虽然在这个教程中不会使用到上面的所有的目录,但是为了以后程序的可拓展性,在一开始就把程序目录设置好使非常必要的。下面就具体说说每个目录的作用:

application – 存放程序代码

config – 存放程序配置或数据库配置

db – 用来存放数据库备份内容

library – 存放框架代码

public – 存放静态文件

scripts – 存放命令行工具

tmp – 存放临时数据

在目录设置好以后,我们接下来就要来顶一下一些代码的规范:

MySQL的表名需小写并采用复数形式,如items,cars

模块名(Models)需首字母大写,并采用单数模式,如Item,Car

控制器(Controllers)需首字母大写,采用复数形式并在名称中添加“Controller”,如ItemsController, CarsController

视图(Views)采用复数形式,并在后面添加行为作为文件,如:items/view.php, cars/buy.php

上述的一些规则是为了能在程序钟更好的进行互相的调用。接下来就开始真正的编码了。

第一步将所有的的请求都重定向到public目录下,解决方案是在todo文件下添加一个.htaccesss文件,文件内容为:

<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule    ^$    public/    [L]
RewriteRule    (.*) public/$1    [L]
</IfModule>

在我们把所有的请求都重定向到public目录下以后,我们就需要将所有的数据请求都再重定向到public下的index.php文件,于是就需要在public文件夹下也新建一个.htaccess文件,文件内容为:

<IfModule mod_rewrite.c>
RewriteEngine On
#如果文件存在就直接访问目录不进行RewriteRule
RewriteCond %{REQUEST_FILENAME} !-f
#如果目录存在就直接访问目录不进行RewriteRule
RewriteCond %{REQUEST_FILENAME} !-d
#将所有其他URL重写到 index.php/URL
RewriteRule ^(.*)$ index.php?url=$1 [PT,L]
</IfModule>

这么做的主要原因有:

可以使程序有一个单一的入口,将所有除静态程序以外的程序都重定向到index.php上;

可以用来生成利于SEO的URL,想要更好的配置URL,后期可能会需要URL路由,这里先不做介绍了。

做完上面的操作,就应该知道我们需要做什么了,没错!在public目录下添加index.php文件,文件内容为:

<?php
    define(&#39;DS&#39;,DIRECTORY_SEPARATOR);
    define(&#39;ROOT&#39;,dirname(dirname(__FILE__)));
    $url = $_GET[&#39;url&#39;];
    require_once(ROOT.DS.&#39;library&#39;.DS.&#39;bootstrap.php&#39;);

注意上面的PHP代码中,并没有添加PHP结束符号”?>”,这么做的主要原因是:对于只包含PHP代码的文件,结束标志(“?>”)最好不存在,PHP自身并不需要结束符号,不添加结束符号可以很大程度上防止末尾被添加额外的注入内容,让程序更加安全。

在index.php中,我们对library文件夹下的bootstrap.php发起了请求,那么bootstrap.php这个启动文件中到底会包含哪些内容呢?

<?php
    require_once(ROOT.DS.&#39;config&#39;.DS .&#39;config.php&#39;);
    require_once(ROOT.DS.&#39;library&#39;.DS .&#39;shared.php&#39;);

以上文件都可以直接在index.php文件中引用,我们这么做的原因是为了在后期管理和拓展中更加的方便,所以把需要在一开始的时候就加载运行的程序统一放到一个单独的文件中引用。

先来看看config文件下的config .php文件,该文件的主要作用是设置一些程序的配置项及数据库连接等,主要内容为:

<?php
    # 设置是否为开发状态
    define(&#39;DEVELOPMENT_ENVIRONMENT&#39;,true);
    # 设置数据库连接所需数据
    define(&#39;DB_HOST&#39;,&#39;localhost&#39;);
    define(&#39;DB_NAME&#39;,&#39;todo&#39;);
    define(&#39;DB_USER&#39;,&#39;root&#39;);
    define(&#39;DB_PASSWORD&#39;,&#39;root&#39;);

应该说config.php涉及到的内容并不多,不过是一些基础数据的一些设置,再来看看library下的共用文件shared.php应该怎么写。

<?php
    /* 检查是否为开发环境并设置是否记录错误日志 */
    function setReporting(){
        if (DEVELOPMENT_ENVIRONMENT == true) {
            error_reporting(E_ALL);
            ini_set(&#39;display_errors&#39;,&#39;On&#39;);
        } else {
            error_reporting(E_ALL);
            ini_set(&#39;display_errors&#39;,&#39;Off&#39;);
            ini_set(&#39;log_errors&#39;,&#39;On&#39;);
            ini_set(&#39;error_log&#39;,ROOT.DS. &#39;tmp&#39; .DS. &#39;logs&#39; .DS. &#39;error.log&#39;);
        }
    }
    /* 检测敏感字符转义(Magic Quotes)并移除他们 */
    function stripSlashDeep($value){
    $value = is_array($value) ? array_map(&#39;stripSlashDeep&#39;,$value) : stripslashes($value);
        return $value;
    }
    function removeMagicQuotes(){
        if (get_magic_quotes_gpc()) {
            $_GET = stripSlashDeep($_GET);
            $_POST = stripSlashDeep($_POST);
            $_COOKIE = stripSlashDeep($_COOKIE);
        }
    }
    /* 检测全局变量设置(register globals)并移除他们 */
    function unregisterGlobals(){
       if (ini_get(&#39;register_globals&#39;)) {
           $array = array(&#39;_SESSION&#39;,&#39;_POST&#39;,&#39;_GET&#39;,&#39;_COOKIE&#39;,&#39;_REQUEST&#39;,&#39;_SERVER&#39;,&#39;_ENV&#39;,&#39;_FILES&#39;);
           foreach ($array as $value) {
               foreach ($GLOBALS[$value] as $key => $var) {
                  if ($var === $GLOBALS[$key]) {
                      unset($GLOBALS[$key]);
                  }
               }
           }
       }
    }
    /* 主请求方法,主要目的拆分URL请求 */
    function callHook() {
        global $url;
        $urlArray = array();
        $urlArray = explode("/",$url);
        $controller = $urlArray[0];
        array_shift($urlArray);
        $action = $urlArray[0];
        array_shift($urlArray);
        $queryString = $urlArray;
        $controllerName = $controller;
        $controller = ucwords($controller);
        $model = rtrim($controller, &#39;s&#39;);
        $controller .= &#39;Controller&#39;;
        $dispatch = new $controller($model,$controllerName,$action);
        if ((int)method_exists($controller, $action)) {
           call_user_func_array(array($dispatch,$action),$queryString);
        } else {
           /* 生成错误代码 */
        }
    }
    /* 自动加载控制器和模型 */
    function __autoload($className) {
        if (file_exists(ROOT . DS . &#39;library&#39; . DS . strtolower($className) . &#39;.class.php&#39;)) {
            require_once(ROOT . DS . &#39;library&#39; . DS . strtolower($className) . &#39;.class.php&#39;);
        } else if (file_exists(ROOT . DS . &#39;application&#39; . DS . &#39;controllers&#39; . DS . strtolower($className) . &#39;.php&#39;)) {
            require_once(ROOT . DS . &#39;application&#39; . DS . &#39;controllers&#39; . DS . strtolower($className) . &#39;.php&#39;);
        } else if (file_exists(ROOT . DS . &#39;application&#39; . DS . &#39;models&#39; . DS . strtolower($className) . &#39;.php&#39;)) {
            require_once(ROOT . DS . &#39;application&#39; . DS . &#39;models&#39; . DS . strtolower($className) . &#39;.php&#39;);
        } else {
           /* 生成错误代码 */
        }
    }
    setReporting();
    removeMagicQuotes();
    unregisterGlobals();
    callHook();

接下来的操作就是在library中建立程序所需要的基类,包括控制器、模型和视图的基类。

新建控制器基类为controller.class.php,控制器的主要功能就是总调度,具体具体内容如下:

<?php
    class Controller {
        protected $_model;
        protected $_controller;
        protected $_action;
        protected $_template;
        function __construct($model, $controller,$action) {
            $this->_controller = $controller;
            $this->_action = $action;
            $this->_model = $model;
            $this->$model =& new $model;
            $this->_template =& new Template($controller,$action);
        }
        function set($name,$value) {
            $this->_template->set($name,$value);
        }
        function __destruct() {
            $this->_template->render();
        }
    }

新建控制器基类为model.class.php,考虑到模型需要对数据库进行处理,所以可以新建一个数据库基类sqlquery.class.php,模型去继承sqlquery.class.php。

新建sqlquery.class.php,代码如下:

<?php
    class SQLQuery {
        protected $_dbHandle;
        protected $_result;
        /** 连接数据库 **/
        function connect($address, $account, $pwd, $name) {
            $this->_dbHandle = @mysql_connect($address, $account, $pwd);
            if ($this->_dbHandle != 0) {
               if (mysql_select_db($name, $this->_dbHandle)) {
                   return 1;
               }else {
                   return 0;
               }
            }else {
               return 0;
            }
         }
        /** 中断数据库连接 **/
        function disconnect() {
             if (@mysql_close($this->_dbHandle) != 0) {
                 return 1;
             } else {
                 return 0;
             }
        }
        /** 查询所有数据表内容 **/
        function selectAll() {
            $query = &#39;select * from `&#39;.$this->_table.&#39;`&#39;;
            return $this->query($query);
        }
        /** 查询数据表指定列内容 **/
        function select($id) {
            $query = &#39;select * from `&#39;.$this->_table.&#39;` where `id` = \&#39;&#39;.mysql_real_escape_string($id).&#39;\&#39;&#39;;
            return $this->query($query, 1);
        }
        /** 自定义SQL查询语句 **/
        function query($query, $singleResult = 0) {
            $this->_result = mysql_query($query, $this->_dbHandle);
            if (preg_match("/select/i",$query)) {
                 $result = array();
                 $table = array();
                 $field = array();
                 $tempResults = array();
                 $numOfFields = mysql_num_fields($this->_result);
                 for ($i = 0; $i < $numOfFields; ++$i) {
                      array_push($table,mysql_field_table($this->_result, $i));
                      array_push($field,mysql_field_name($this->_result, $i));
                  }
                 while ($row = mysql_fetch_row($this->_result)) {
                     for ($i = 0;$i < $numOfFields; ++$i) {
                        $table[$i] = trim(ucfirst($table[$i]),"s");
                        $tempResults[$table[$i]][$field[$i]] = $row[$i];
                     }
                     if ($singleResult == 1) {
                         mysql_free_result($this->_result);
                         return $tempResults;
                     }
                     array_push($result,$tempResults);
                 }
                 mysql_free_result($this->_result);
                 return($result);
             }
          }
         /** 返回结果集行数 **/
        function getNumRows() {
            return mysql_num_rows($this->_result);
        }
        /** 释放结果集内存 **/
        function freeResult() {
            mysql_free_result($this->_result);
        }
       /** 返回MySQL操作错误信息 **/
       function getError() {
           return mysql_error($this->_dbHandle);
       }
    }

新建model.class.php,代码如下:

<?php
    class Model extends SQLQuery{
        protected $_model;
        function __construct() {
            $this->connect(DB_HOST,DB_USER,DB_PASSWORD,DB_NAME);
            $this->_model = get_class($this);
            $this->_table = strtolower($this->_model)."s";
        }
        function __destruct() {
        }
    }

新建视图基类为template.class.php,具体代码如下:

<?php
    class Template {
       protected $variables = array();
       protected $_controller;
       protected $_action;
       function __construct($controller,$action) {
           $this->_controller = $controller;
           $this->_action =$action;
       }
       /* 设置变量 */
       function set($name,$value) {
            $this->variables[$name] = $value;
       }
       /* 显示模板 */
       function render() {
           extract($this->variables);
           if (file_exists(ROOT.DS. &#39;application&#39; .DS. &#39;views&#39; .DS. $this->_controller .DS. &#39;header.php&#39;)) {
               include(ROOT.DS. &#39;application&#39; .DS. &#39;views&#39; .DS. $this->_controller .DS. &#39;header.php&#39;);
           } else {
               include(ROOT.DS. &#39;application&#39; .DS. &#39;views&#39; .DS. &#39;header.php&#39;);
           }
           include (ROOT.DS. &#39;application&#39; .DS. &#39;views&#39; .DS. $this->_controller .DS. $this->_action . &#39;.php&#39;);
           if (file_exists(ROOT.DS. &#39;application&#39; .DS. &#39;views&#39; .DS. $this->_controller .DS. &#39;footer.php&#39;)) {
               include (ROOT.DS. &#39;application&#39; .DS. &#39;views&#39; .DS. $this->_controller .DS. &#39;footer.php&#39;);
           } else {
               include (ROOT.DS. &#39;application&#39; .DS. &#39;views&#39; .DS. &#39;footer.php&#39;);
           }
        }
    }

做完了以上这么多操作,基本上整个MVC框架已经出来了,下面就该制作我们的站点了。我们要做的站点其实很简单,一个ToDo程序。

首先是在我们的/application/controller/ 目录下面新建一个站点控制器类为ItemsController,命名为itemscontroller.php,内容为:

<?php
    class ItemsController extends Controller {
       function view($id = null,$name = null) {
           $this->set(&#39;title&#39;,$name.&#39; - My Todo List App&#39;);
           $this->set(&#39;todo&#39;,$this->Item->select($id));
       }
       function viewall() {
           $this->set(&#39;title&#39;,&#39;All Items - My Todo List App&#39;);
           $this->set(&#39;todo&#39;,$this->Item->selectAll());
       }
       function add() {
           $todo = $_POST[&#39;todo&#39;];
           $this->set(&#39;title&#39;,&#39;Success - My Todo List App&#39;);
           $this->set(&#39;todo&#39;,$this->Item->query(&#39;insert into items (item_name) values (\&#39;&#39;.mysql_real_escape_string($todo).&#39;\&#39;)&#39;));
       }
       function delete($id) {
           $this->set(&#39;title&#39;,&#39;Success - My Todo List App&#39;);
           $this->set(&#39;todo&#39;,$this->Item->query(&#39;delete from items where id = \&#39;&#39;.mysql_real_escape_string($id).&#39;\&#39;&#39;));
       }
    }

接下来就是先建站点的模型,在我们的/application/model/ 目录下面先建一个站点模型类为Item,内容直接继承Model,代码如下:

<?php
class Item extends Model {
}

最后一步是设置我们站点的视图部分,我们现在/application/views/目录下新建一个items的文件夹,再在items文件夹下建立与控制器重Action相同的文件,分别为view.php,viewall.php,add.php,delete.php,考虑到这么页面中可能需要共用页首和页尾,所以再新建两个文件,命名为header.php,footer.php,每个文件的代码如下:

view.php文件:查看单条待处理事务

<h2><?php echo $todo[&#39;Item&#39;][&#39;item_name&#39;]?></h2>
<a href="../../../items/delete/<?php echo $todo[&#39;Item&#39;][&#39;id&#39;]?>">
<span>Delete this item</span>
</a>

viewall.php文件:查看所有待处理事务

<form action="../items/add" method="post">
    <input type="text" value="I have to..." onclick="this.value=&#39;&#39;" name="todo"> <input type="submit" value="add">
</form>
<br/><br/>
<?php $number = 0?>
<?php foreach ($todo as $todoitem):?>
    <a href="../items/view/<?php echo $todoitem[&#39;Item&#39;][&#39;id&#39;]?>/<?php echo strtolower(str_replace(" ","-",$todoitem[&#39;Item&#39;][&#39;item_name&#39;]))?>">
        <span>
            <?php echo ++$number?>
            <?php echo $todoitem[&#39;Item&#39;][&#39;item_name&#39;]?>
        </span>
    </a><br/>
<?php endforeach?>

add.php文件:添加待处理事务

<a href="../items/viewall">Todo successfully added. Click here to go back.</a><br/>

delete.php文件:删除事务

<a href="../../items/viewall">Todo successfully deleted. Click here to go back.</a><br/>

header.php:页首文件

<html>
<head>
<title><?php echo $title?></title>
<style>
.item {width:400px;}
input {color:#222222;font-family:georgia,times;font-size:24px;font-weight:normal;line-height:1.2em;color:black;}
a {color:#222222;font-family:georgia,times;font-size:24px;font-weight:normal;line-height:1.2em;color:black;text-decoration:none;}
a:hover {background-color:#BCFC3D;}
h1 {color:#000000;font-size:41px;letter-spacing:-2px;line-height:1em;font-family:helvetica,arial,sans-serif;border-bottom:1px dotted #cccccc;}
h2 {color:#000000;font-size:34px;letter-spacing:-2px;line-height:1em;font-family:helvetica,arial,sans-serif;}
</style>
</head>
<body>
<h1>My Todo-List App</h1>

footer.php:页尾文件

</body>
</html>

当然还有一个必不可少的操作就是在数据中中建立一张表,具体代码如下:

CREATE TABLE IF NOT EXISTS `items` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `item_name` varchar(255) NOT NULL,
    PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=17 ;

至此一个使用MVC开发的网站就开发完成了,你现在可以通过访问http://localhost/todo/items/viewall 查看新建的站点。


声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
PHP类型提示如何起作用,包括标量类型,返回类型,联合类型和无效类型?PHP类型提示如何起作用,包括标量类型,返回类型,联合类型和无效类型?Apr 17, 2025 am 12:25 AM

PHP类型提示提升代码质量和可读性。1)标量类型提示:自PHP7.0起,允许在函数参数中指定基本数据类型,如int、float等。2)返回类型提示:确保函数返回值类型的一致性。3)联合类型提示:自PHP8.0起,允许在函数参数或返回值中指定多个类型。4)可空类型提示:允许包含null值,处理可能返回空值的函数。

PHP如何处理对象克隆(克隆关键字)和__clone魔法方法?PHP如何处理对象克隆(克隆关键字)和__clone魔法方法?Apr 17, 2025 am 12:24 AM

PHP中使用clone关键字创建对象副本,并通过\_\_clone魔法方法定制克隆行为。1.使用clone关键字进行浅拷贝,克隆对象的属性但不克隆对象属性内的对象。2.通过\_\_clone方法可以深拷贝嵌套对象,避免浅拷贝问题。3.注意避免克隆中的循环引用和性能问题,优化克隆操作以提高效率。

PHP与Python:用例和应用程序PHP与Python:用例和应用程序Apr 17, 2025 am 12:23 AM

PHP适用于Web开发和内容管理系统,Python适合数据科学、机器学习和自动化脚本。1.PHP在构建快速、可扩展的网站和应用程序方面表现出色,常用于WordPress等CMS。2.Python在数据科学和机器学习领域表现卓越,拥有丰富的库如NumPy和TensorFlow。

描述不同的HTTP缓存标头(例如,Cache-Control,ETAG,最后修饰)。描述不同的HTTP缓存标头(例如,Cache-Control,ETAG,最后修饰)。Apr 17, 2025 am 12:22 AM

HTTP缓存头的关键玩家包括Cache-Control、ETag和Last-Modified。1.Cache-Control用于控制缓存策略,示例:Cache-Control:max-age=3600,public。2.ETag通过唯一标识符验证资源变化,示例:ETag:"686897696a7c876b7e"。3.Last-Modified指示资源最后修改时间,示例:Last-Modified:Wed,21Oct201507:28:00GMT。

说明PHP中的安全密码散列(例如,password_hash,password_verify)。为什么不使用MD5或SHA1?说明PHP中的安全密码散列(例如,password_hash,password_verify)。为什么不使用MD5或SHA1?Apr 17, 2025 am 12:06 AM

在PHP中,应使用password_hash和password_verify函数实现安全的密码哈希处理,不应使用MD5或SHA1。1)password_hash生成包含盐值的哈希,增强安全性。2)password_verify验证密码,通过比较哈希值确保安全。3)MD5和SHA1易受攻击且缺乏盐值,不适合现代密码安全。

PHP:服务器端脚本语言的简介PHP:服务器端脚本语言的简介Apr 16, 2025 am 12:18 AM

PHP是一种服务器端脚本语言,用于动态网页开发和服务器端应用程序。1.PHP是一种解释型语言,无需编译,适合快速开发。2.PHP代码嵌入HTML中,易于网页开发。3.PHP处理服务器端逻辑,生成HTML输出,支持用户交互和数据处理。4.PHP可与数据库交互,处理表单提交,执行服务器端任务。

PHP和网络:探索其长期影响PHP和网络:探索其长期影响Apr 16, 2025 am 12:17 AM

PHP在过去几十年中塑造了网络,并将继续在Web开发中扮演重要角色。1)PHP起源于1994年,因其易用性和与MySQL的无缝集成成为开发者首选。2)其核心功能包括生成动态内容和与数据库的集成,使得网站能够实时更新和个性化展示。3)PHP的广泛应用和生态系统推动了其长期影响,但也面临版本更新和安全性挑战。4)近年来的性能改进,如PHP7的发布,使其能与现代语言竞争。5)未来,PHP需应对容器化、微服务等新挑战,但其灵活性和活跃社区使其具备适应能力。

为什么要使用PHP?解释的优点和好处为什么要使用PHP?解释的优点和好处Apr 16, 2025 am 12:16 AM

PHP的核心优势包括易于学习、强大的web开发支持、丰富的库和框架、高性能和可扩展性、跨平台兼容性以及成本效益高。1)易于学习和使用,适合初学者;2)与web服务器集成好,支持多种数据库;3)拥有如Laravel等强大框架;4)通过优化可实现高性能;5)支持多种操作系统;6)开源,降低开发成本。

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
1 个月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
1 个月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
1 个月前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.聊天命令以及如何使用它们
1 个月前By尊渡假赌尊渡假赌尊渡假赌

热工具

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

安全考试浏览器

安全考试浏览器

Safe Exam Browser是一个安全的浏览器环境,用于安全地进行在线考试。该软件将任何计算机变成一个安全的工作站。它控制对任何实用工具的访问,并防止学生使用未经授权的资源。

WebStorm Mac版

WebStorm Mac版

好用的JavaScript开发工具

mPDF

mPDF

mPDF是一个PHP库,可以从UTF-8编码的HTML生成PDF文件。原作者Ian Back编写mPDF以从他的网站上“即时”输出PDF文件,并处理不同的语言。与原始脚本如HTML2FPDF相比,它的速度较慢,并且在使用Unicode字体时生成的文件较大,但支持CSS样式等,并进行了大量增强。支持几乎所有语言,包括RTL(阿拉伯语和希伯来语)和CJK(中日韩)。支持嵌套的块级元素(如P、DIV),