tp5.1学习笔记1

[TOC]

安装

composer create-project topthink/think tp5

配置文件:

默认配置都在app.php配置文件,并且配置参数区分大小写

两种层级的配置:

  • 应用配置目录 config

  • 模块配置目录 application/module/config

    以上两种配置,只能有一种生效。如果模块module下面有config配置,那么此模块,应用此配置。全局配置失效。

快速入门

  • 控制器

    默认继承controller。访问:http://localhost/tp/public/index.php/index/index/index 其中,index.php后面,模→控→操

    命名空间:app\index\controller 除了app是缩写,其他都代表真实的路径。

    <?php
    namespace app\index\controller;
    
    use \think\Controller;
    
    class Index extends Controller
    {
        public function index()
        {
    		return '<h1>Hello world</h1>';
        }
    
        public function hello($name = 'ThinkPHP5')
        {
            return 'hello,' . $name;
        }
        public function test(){
            echo \json_encode(['age'=>123,'name'=>'']);
        }
        public function test1(){
            $data = ['age'=>123,'name'=>'wangduoduo'];
            return xml($data);//或json
        }
    }

    提交的参数:

    $this->request   对象。
    $this->request->param('name')   
    $this->request->get('name')  //进行了区分。
    $data = $this->request->param();//返回所有的提交数据

    返回数据:

    return json($data); 注意: 如果是使用了助手函数,请return。如果echo,则会报错。因为框架,会根据控制器的返回,进行处理。

    常见的助手函数,json/xml等。

  • 配置连数据库等

    数据库的配置 application/config/database.php 简单的更新如下的几个配置即可。

    'type'            => 'mysql',
    // 服务器地址
    'hostname'        => '127.0.0.1',
    // 数据库名
    'database'        => 'test',
    // 用户名
    'username'        => 'root',
    // 密码
    'password'        => 'root',

测试表:

CREATE TABLE `user` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(64) DEFAULT NULL,
  `sex` int(1) DEFAULT NULL,
  `age` tinyint(3) unsigned DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=2 DEFAULT CHARSET=utf8

测试查询数据

use \think\Db;    //导入类

//返回查询数据
public function index(){   
	$data = Db::connect()
		->table('user')
		->select();
	return json($data);
}

备注:查询find 跟select的区别,find即findOne,而select 是取出所有匹配的结果集。官方文档如此备注:默认情况下,findselect方法返回的都是数组,区别在于后者是二维数组。

添加数据:

public function add(){   
	$data = $this->request->param(); 
	// Db::name('user')->insert($data);   //方式一
	Db::name('user')->data($data)->insert();  //方式二
}

更新数据:

public function update(){
	Db::name('user')
		->where('id', 1)
		->update(['name' => '猪大强']);
}

删除数据:

// 根据主键删除
Db::table('think_user')->delete(1);
Db::table('think_user')->delete([1,2,3]);

// 条件删除    
Db::table('think_user')->where('id',1)->delete();
Db::table('think_user')->where('id','<',10)->delete();

如上,基本完成了增删改查的功能。

  • 数据验证

    每个字段增加若干个验证规则,以|分隔。如果有详细的规则,以冒号:逗号,来描述。验证为假,并不会阻止表单的的insert行为,而是自己需要手动的根据判断结果来控制。

    <?php
    /**
     * 2019-08-19 17:06:38
     */
    namespace app\index\validate;
    
    use think\Validate;
    
    class User extends Validate{
    	protected $rule = [
    		'name'=>'require|max:25',
    		'age'=>'number|between:1,150',
    		'sex'=>'number|between:1,2'
    	];
    	protected $message = [
    		'name.require' =>'姓名是必填字段',
    		'name.max' =>'姓名最多不能超过25个字',
    		'age.number' =>'年龄必须是数字',
    		'age.between' =>'年龄只能在1-120之间',
    		'sex.number' =>'性别填写有误',
    		'sex.between' =>'性别填写有误'
    	];
    }

    也可以使用数组来定义。

    控制器内,进行验证。

    //数据验证,可选。 推荐使用这种方式。
    $validate = new \app\index\validate\User; 
    if (!$validate->batch()->check($data)) {
    	dump($validate->getError());
    	exit;
    }

小结

按照完整的业务流程,应该包含提供数据展示,数据的提交表单,用户提交表单后,前端要对数据进行验证,后端过滤用户数据,后端进行数据验证(数据格式的验证、业务逻辑验证),数据入库。数据处库时,也要验证。上面的例子将所有的逻辑,都写在的控制器内。后期应该更改。

接下来,应该学习:

路由功能、数据库高级查询功能、

配置文件

应用配置

config/app.php配置文件直接返回一个数组。估计在调用的时候,$cfg = include ‘app.php’类似的调用方式。

  • app_debug

    很重要,开启调试模式。能在调试的时候,看到直观的错误提示。

  • app_trace

    开启html模式下,返回的性能跟踪工具。

config/database.php数据库配置。

模块配置

例如为index模块增加单独的数据库配置文件。拷贝config/database.php→

application\index\config\database.php

然后,在上面的文件中设置独立的数据库连接信息。

备注:config是跟application同级目录。

钩子和行为

参照架构→总览的例子

类似于AOP编程中的“切面”的概念,给某一个钩子绑定相关行为就成了一种类AOP编程的思想。

这里面有两个概念,一个是钩子,另外一个是行为。

  • 钩子,类似于Extjs中的fireEvent,表示要触发的地方。

  • 行为,类似于Extjs中的on,表示要执行回调的地方。

    总结:行为的类,要实现run方法。关于顺序,肯定是先on,然后再fireEvent。

官网提了示例的代码,但是没有告诉这些代码放在哪。behavior类如何编写等。经过试探,总结如下:

  • 先定义add的监听的方法,然后才能去监听,listen。

  • 新建目录,application\index\behavior新建一个类,该类必须要有一个run方法。方法:public function run

相关代码:

在控制器类,添加(演示,都放到一起了。):

\think\facade\Hook::add('app_init','\app\index\behavior\Applisten');
\think\facade\Hook::listen('app_init');

定义具体的类。

<?php
/**
 * 2019-08-20 11:30:11
 */
namespace app\index\behavior;

class Applisten {
    public function run(){
        echo __FILE__."   app_init ";
    }
}

中间件

事件

主要是数据库增删改查的事件。又分为模型事件、数据库操作事件。

think\Model::beforeUpdate($callback, $override = false)

但是,这个事件,比以前的tp3.2的复杂了很多。之前的版本,实际上就是,在相关事件中,调用模型的方法而已。

数据库操作事件

public function update(){
	Db::event('after_update', function($query){
		var_dump($query); //think\db\Query对象
		return $query;  //不return,应该也没有问题。
	});
	Db::name('user')
	->where('id', 1)
	->update(['name' => '强大强12']);
}

说明:上面的after_update是在update之后才会触发,如果没有更改,则不会触发。如果update执行多个,估计都会执行回调?

不太明白,为啥before_update没有触发。难道,真的是框架上说明的那样(架构→架构总览),数据库查询支持的只有before_select。before_find、after_insert、after_update、after_delete。

模型事件

这个很难理解。

public function update(){
	$user = new \app\index\model\User;
	$user::beforeUpdate(function($query){
		echo '1234314';
	});
	$user->where('id',1)->update(['name' => '强大强11']);
}

结果还抛出异常。

method not exist:app\index\model\User->beforeUpdate

架构

Facade

说的直白一点,Facade功能可以让类无需实例化而直接进行静态方式调用。

框架内部默认已经包含了一些实现。参见thinkphp\library\think。 仿照这些,可以写自己的demo。通过增加定义一个类,来减少调用时,像使用静态方法那样直接调用。

简单的demo

//在入口控制器内增加如下:
\app\index\facade\User::sayhello();

增加类文件application\index\facade\User.php:

namespace app\index\facade;

class User extends \think\Facade{
    protected static function getFacadeClass()
    {
        return 'app\index\model\User';
    }
}

然后就能直接使用未经实例化的model对象的方法呢。

注意:

1、在进行类型约束的时候,要用原本的类来进行约束。

2、框架默认为一些类,提供了别名,即更简短的名称。

3、facada这种类,对编辑器不友好,代码自动提示有问题。增加_ide_helper.php文件(具体如何实现?我也不清楚)

入口

[ Apache ]

  1. httpd.conf配置文件中加载了mod_rewrite.so模块

  2. AllowOverride NoneNone改为 All

  3. 把下面的内容保存为.htaccess文件放到应用入口文件的同级目录下(Server API: Apache 2.0 Handler)

<IfModule mod_rewrite.c>
  Options +FollowSymlinks -Multiviews
  RewriteEngine On

  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteRule ^(.*)$ index.php/$1 [QSA,PT,L]
</IfModule>

上面的重写机制好像是要求,必须放到文件的根目录中。没有放到根目录中,就提示,文件不存在。

错误提示如下:

No input file specified.

需要注意如下:

查看phpinfo() 打印的,如果是Server API: CGI/FastCGI,而phpstudy中正好是这种。

RewriteRule ^(.)$ index.php/$1 [QSA,PT,L]
必须改成
RewriteRule ^(.)$ index.php?/$1 [QSA,PT,L]
还可以改写成如下:
RewriteRule ^(.)$ index.php [L,E=PATH_INFO:$1]   //推荐这种,在子目录下,也能使用

完整如下:

<IfModule mod_rewrite.c>
  Options +FollowSymlinks -Multiviews
  RewriteEngine On

  RewriteCond %{REQUEST_FILENAME} !-d
  RewriteCond %{REQUEST_FILENAME} !-f
  RewriteRule ^(.*)$ index.php [L,E=PATH_INFO:$1]
</IfModule>

另外,还可能有FPM/FastCGI这种形式。说明是nginx服务器。

换用之前项目中的方式,提示找不到tp模块。

RewriteEngine on
RewriteRule !\.(pdf|ps|js|ico|gif|jpg|png|bmp|css|JPG|xap|xml|xls|json|html|swf|cab|mp3|wav)$ index.php

试过了,想要放到子目录中,都不好使。

助手函数

命令行

大概也就几种。说白了,就是根据模板自动生成一些空白的代码模板。(也没有啥大用,完全可以用自己的模板生成工具。)好总比没有强。

总共也就下面的几种:

make:command
make:controller
make:model
make:middleware
make:validate
  • 中间件
php think make:middleware Check
  • 模型
//这个在common模块中生成
php think make Test
//这个制定了模块
php think make:model index/Test 
  • 控制器
php think make:controller index/Hello
  • 验证器
php think make:validate index/Hello

框架源码

延迟绑定

第一次听到这个词,是因为看了Container的实现。new static。实在是不理解。就百度了。

public static function getInstance()
    {
        if (is_null(static::$instance)) {
            static::$instance = new static;
        }

        return static::$instance;
    }

总结:new static 跟new self 两者都是实例化自身,区别在于继承。如果没有继承,则两者返回的实例都是属于一个类;如果有继承,子类调用该方法,new self 仍然返回原类的实例,而 new static 返回实际子类的实例。这就是延迟静态绑定,static 的值,使用的是最后实际调用那个方法的类。

参见理解 php new static