Home > Article > Backend Development > Detailed explanation of ThinkPHP framework design and extension, detailed explanation of thinkphp framework_PHP tutorial
ThinkPHP framework is a well-known and widely used PHP framework in China. Let’s take a closer look at the development convenience this framework brings to us and its easy expansion design through some simple development examples. At the same time, we also look at some shortcomings of the framework from the perspective of source code analysis, and try to make a comprehensive and objective evaluation. It is assumed here that you have already used the ThinkPHP framework. Please refer to the official documentation for basic usage.
1. Framework layering and url routing
The installation of the framework is very simple. Just download it and put it in the directory of the web server. However, it is recommended that you do not use the default entry file location, but put it in a separate directory to protect the code and data. For example, my entry file and web server configuration directory are in the web directory (index.php in the outer frame is not deleted but not used):
Like most MVC frameworks, we only need to extend our own Controller and View according to the directory structure of the framework, and some pages are developed. ThinkPHP provides a three-layer structure of Module, Controller, and Action to organize its own URLs (version 3.1 is called grouping, action, and method, and 3.2 is more international). The directory structure is as follows:
Here we strongly recommend:
1. The business is layered separately and does not need to be placed in the Controller and Model. For example, I use the extended function library Application/Common/Common/function.php to forcefully define the business layer name as Service:
<code>function service($name)<br>{<br> return D($name, 'Service');<br>}</code>
The advantage is that it is reusable. If you want to develop wap pages in the future and write different Controllers, you can reuse the service. If the data storage changes in the future, such as migrating the database from MySQL to MongoDB, then modify it. The Model is fine, but the service still does not need any modification.
2. Basic modules and business modules should be separated and should not reference each other. Basic modules (such as basic user information) only provide data interfaces without Controller and View.
The three-layer directory can already handle general web applications. For more complex web applications, we can define different entry files and load different Applications to solve them. More complex applications? For portals and very large-scale websites, a PHP framework cannot solve all problems. It requires its own middleware and customized framework.
ThinkPHP supports 4 url access modes , which are:
1. Normal mode , traditional url mode, all parameters are separated, such as
http://localhost/tp/index.php?m=Ucai&c=User&a=index¶=xxx
Routing parameters: m parameter represents module, c represents controller, a represents access method
2. Compatibility mode
http://localhost/tp/index.php?s=/Ucai/User/index/para/xxx
Routing parameters are assembled through s parameters. Of course, data parameters do not need to be placed in s parameters
3. pathinfo mode
http://localhost/tp/index.php/Ucai/User/index/para/xxx
This mode puts the entry file and the real script together, which has clear meaning and is also convenient for SEO
4. rewrite mode
http://localhost/tp/Ucai/User/index/para/xxx
This mode hides the entry file through the rewrite configuration of the web server, making it more friendly
The pathinfo and rewrite modes require web server support. ThinkPHP has a configuration that needs to be set to which mode. It is actually used when generating url links in the U method. When accessing, any method can be used as long as the web server supports it.
It is also recommended that ThinkPHP does not need to be configured, but remembers the user's access method. As long as the first access mode is used, all subsequent URLs will be generated in this way, because the user has already accessed it and there is no support. No support issue.
If the normal URL cannot meet our requirements, you can further optimize the URL by configuring routing. For example, we want to configure the URL more simply
http://localhost/tp/Ucai/login/xxx
We only need to add the following routing configuration to the module configuration file. It can be more simplified if we use regular expressions
<code>'URL_ROUTE_RULES' => array(<br> 'login/:para' => 'Ucai/User/index',<br> 'login' => 'Ucai/User/index',<br> ),</code>
Here we can see that the ThinkPHP framework supports a very rich hierarchy and url configuration, which can meet various needs. Of course, we recommend that you do not abuse routing configuration. A small amount of appropriate configuration can bring better SEO effects, but a large number of configurations will bring difficulties to the maintenance and modification of the project.
2. ThinkPHP extension
ThinkPHP itself contains a wealth of components and drivers. Let’s take database driver extensions and behavioral extensions as examples to understand the extension design of ThinkPHP.
3. Database driver extension
虽然ThinkPHP提供了众多的数据库驱动,但是也并不能满足所有的需求。例如我们的数据很可能不是通过直接访问数据库去实现,而是通过一些中间件(例如C程序)进行转发,从而获得更好的性能,这时就需要扩展数据库驱动来支持。
扩展非常简单,在DB/Driver目录下新建自己的驱动,例如Custom.php,然后实现request和execute方法扩展就算完成了,然后再配置文件里配置DB_TYPE='custom',就可以使用了。这里的request表示查询,execute表示更改数据,所有其他操作都会在Model里进行解析,包装成sql语句调用这两个方法执行。
例如我所实现的最简单的query方式,通过shell命令调用sqlite执行sql语句:
<code>public function query($str) {<br> $cmd = sprintf('sqlite3 %s "%s"', $this->config['params']['dbfile'], $str);<br> exec($cmd, $arr);<br>}</code>
当然这个只是示例,ThinkPHP本身就支持sqlite3,通过pdo的方式去连接就可以。实际的应用环境可能是通过连接4层协议访问中间层端口获取数据。
四、Behavior行为扩展
Behavior行为设计是ThinkPHP框架的核心,通过行为配置和扩展,为系统的伸缩性和定制性提供了最大的支持。
假如我们要加入登录验证的功能,按照常规我们会设计自己的父类Controller,然后所有其他的Controller都从这里继承。但有了Behavior会变得更加简单和灵活,我们只需要在tags.php(没有的话在配置目录新建)添加一个Behavior就可以了:
<code>return array(<br> 'action_begin' => array('Ucai\Behavior\AuthBehavior'),<br> 'view_begin' => array('Ucai\Behavior\OutputBehavior'),<br>);</code>
程序在执行到action_begin流程时就会调用这个Behavior,我们可以根据状态进行跳转或终止执行。
<code>namespace Ucai\Behavior;<br>class AuthBehavior {<br> // 行为扩展的执行入口必须是run<br> public function run(&$return) {<br> //不需要验证的action设置为true<br> if (!$return['AUTH_PUBLIC']) {<br> if (service('User')->checkLogin())<br> {<br> $return = true;<br> }<br> else<br> {<br> header('Content-Type: text/html; charset=utf-8');<br> redirect(U('User/index', array('url' => $_SERVER['HTTP_REFERER'])), 5, '需要登录,5秒后跳转。。。');<br> }<br> }<br> }<br>}</code>
对于不需要登录的页面我们可以在Controller里添加配置,所有不配置的都会要求登录验证。
<code>public $config = array('AUTH_PUBLIC' => true);</code>
这里大家对继承和Behavior实现登录验证做一个对比,可能觉得区别不大。但是在一个复杂的项目里,这种功能会非常多,如果每个功能都放到父类里,就会非常庞大,并且部分子类可能又不需要,这时候用Behavior去定制流程就会显得游刃有余。
在上面的配置中我们还发现了一个配置OutputBehavior更能说明问题,大家有没有猜到,这个Behavior我是用来在view里输出一些共有变量,例如jscss的域名和路径等。在没有Behavior之前,大家是不是需要一个公共方法,然后每个页面都去调用一次,或者改写View的类代码?有了Behavior就显得方便许多。
<code>namespace Ucai\Behavior;<br>class OutputBehavior {<br> public function run(&$return) {<br> $view = \Think\Think::instance('Think\View');<br> $view->assign('STATIC_URL', 'http://p3.ucai.cn/static');<br> }<br>}</code>
扩展总结:通过Behavior扩展和数据库驱动扩展大家可以看到,ThinkPHP提供了很灵活的扩展和增强机制,能满足众多需求。其他存储、缓存、日志、模板引擎等如果需要也能很方便的扩展。
五、源码分析与不足
首先我们来分析一下框架执行的大致流程:
index.php(入口、调试模式、应用路径)
--> ThinkPHP.php(定义路径与访问模式)
--> Think\Think(类加载器、异常处理、读取共有配置)
--> Think\App(请求url调度解析、执行调度解析结果)
--> exec 执行用户定义的Controller的Action方法
--> Think\Dispatcher(根据url模式解析M、C、A和参数,加载模块配置)
--> Think\Controller(调用视图、包装和重定向)
可以看到,框架的内部流程其实比较简单,还有2个很重要的类:
Think\Hook: 监听App、Action、View的各个阶段,执行Behavior
Think\Behavior: 可配置(配置文件)可增删(代码)
在分析源代码的过程中,我们也看到了一些不足:
1、宏定义过多,难于维护和修改
建议:只在个别文件定义极少数几个宏,其余用类常量包装
2、面向过程代码过多,封装不清晰
建议:用面向对象思想包装
例如:url的解析和包装,现在是在Dispatcher里生成APP宏,然后在U方法里读取宏并生成最终url。其实完全可以定义一个类来包装例如UrlHelper,而类的二个方法parse和generate分别负责解析和生成url,这样代码结构会清晰很多。
3、有的函数和类代码封装过多,复用和改进不方便
建议:用组合来封装独立功能内容
例如:Model的校验功能,完全可以独立成类,也可以用于非Model对象调用。而现在的校验接口是Model的保护性方法,只能在Model的create函数调用,外面必须通过create方法才能校验。
4、代码规范和风格问题
希望代码风格能更加规范和标准,例如DB类作为模板方法的父类,应该用抽象方法或抛出异常形式定义所有Model需用到的方法。事实上有些方法子类是不需要的,而Db类却没有实现。
六、总结
ThinkPHP, as a popular PHP framework in China, has indeed brought convenience to our development. Framework developers have a thorough understanding of web processes and are proficient in PHP function applications. The framework defines flexible configuration and extension to adapt to various needs, and provides a wealth of components and modules to accelerate development. Finally, ThinkPHP’s documentation and community support are very complete, which is also an indispensable part of the popularity of the framework. We also hope that ThinkPHP can further improve its structure in the future and build the best PHP framework.