## 练习1:Hello,ThinkPHP
>[info] 任务:在安装完成后来完成第一个实例代码,要求运行后显示`Hello,ThinkPHP!`。
### 实现一:路由实现
针对这个需求的最简单实现,是在路由定义文件(`route/route.php`)开头添加如下代码:
~~~
Route::get('/', function () {
return 'Hello,ThinkPHP!';
});
~~~
然后直接访问(这里使用了上一个练习的内容提到的`Vhost`访问)
~~~
http://tp5.com
~~~
页面输出:
~~~
Hello,ThinkPHP!
~~~
是不是很简单?直接通过路由定义返回页面输出内容(更多的路由用法我们后面还会陆续提到,暂且不表)。接下来,我们来看第二种实现代码,通过标准的控制器来实现。
### 实现二:控制器实现
进入`CMD`命令行,切换到应用根目录(也就是`tp5`目录),执行下面的指令:
~~~
php think make:controller index/Hello --plain
~~~
会自动生成一个控制器文件,位于:
~~~
application/index/controller/Hello.php
~~~
在编辑器打开,可以看到已经生成了一个空的控制器(类)文件
~~~
<?php
namespace app\index\controller;
use think\Controller;
class Hello extends Controller
{
//
}
~~~
> 后面再提到控制器的时候,你的第一反应就是这个`controller`目录下面的某个类,而且从类名就能直观看出控制器名,从命名空间可以找到所在位置。
我们在控制器类里面添加一个`index`方法(必须使用`public`类型,一般我们称为操作方法,它是URL访问的最小单元),内容如下:
~~~
<?php
namespace app\index\controller;
use think\Controller;
class Hello extends Controller
{
// 显示欢迎页面
public function index()
{
return 'Hello,ThinkPHP!';
}
}
~~~
> 今后提到控制器的某个操作,你的第一反应就是去找这个控制器下面的某个方法。
然后我们直接在浏览器中访问
~~~
http://tp5.com/index/hello
~~~
页面输出:
~~~
Hello,ThinkPHP!
~~~
至此,我们完成了一个标准的控制器输出`Hello,ThinkPHP`的实现代码。
## 拓展讨论
### 为何用`return`而不用`echo`
我们看到控制器的操作方法都是直接`return`的,而没有使用我们习惯的`echo`方法输出。你会发现使用`echo`输出的话,最终的结果其实是一样的,但为什么不建议使用呢?
确实,如果你要输出的数据本身就是字符串的话,使用`echo`的结果是一样的,但ThinkPHP的控制器操作方法支持不同的响应输出(甚至需要设置不同的头信息),对于不同的响应输出会调用不同的`Response`子类,例如`JSON`、`XML`等,你可以直接`return`一个数组或者对象数据,然后交给`Response`来处理转换,甚至你可以直接return一个`Response`对象。还有一种情况是,你可以统一使用系统提供的钩子对响应输出进行额外的处理,而如果你使用了`echo`直接输出,将无法享受这些功能特性。
>[info] 关于更多的`Response`响应处理的知识,我们后面还会陆续提到,暂且不用深究,但请保持操作方法统一`return`的习惯(除非在操作方法中间进行调试的时候可以使用`echo`或者`dump`)。
### 更优雅的URL
是否觉得
~~~
http://tp5.com/index/hello
~~~
这个访问地址有点太长了,似乎不够优雅,没关系,我们马上来改进下。
打开路由定义文件`route/route.php`,添加一行代码如下:
~~~
Route::get('hello','Hello/index');
~~~
现在你可以优雅的访问
~~~
http://tp5.com/hello
~~~
输出同样的内容。
### 添加URL变量
我们希望欢迎页面能显示输入的名称,而不是ThinkPHP,就需要用到URL变量,我们分别针对上述两种实现来进行调整。
如果是第一种,我们修改路由定义如下:
~~~
Route::get('hello/:name', function ($name) {
return 'Hello,' . $name . '!';
});
~~~
>[info] 你暂时不用深究路由传递参数的原理,你只需要记得使用`:name`就表示URL中输入的变量,然后可以在闭包中调用该同名变量。
直接访问
~~~
http://tp5.com/hello/张三
~~~
页面输出结果:
~~~
Hello,张三!
~~~
你可以尝试更改URL地址`hello`后面的名称来查看输出结果。
如果是第二种实现,首先把路由定义改成
~~~
Route::get('hello/:name','Hello/index');
~~~
然后对`Hello`控制器类的`index`方法稍加调整。
~~~
<?php
namespace app\index\controller;
use think\Controller;
class Hello extends Controller
{
// 显示欢迎页面
public function index($name='ThinkPHP')
{
return 'Hello,' . $name . !';
}
}
~~~
>[info] 没有比这更神奇的事情了,路由地址中的变量`name`可以很神奇的传递到`index`方法中。
直接访问
~~~
http://tp5.com/hello/李四
~~~
页面输出结果:
~~~
Hello,李四!
~~~
### 添加类库后缀
为了尽量避免关键字的冲突,我们可以统一开启类库后缀功能,在应用根目录下的`config`目录下找到`app.php`文件,打开后更改下面的配置参数:
~~~
// 开启应用类库后缀
'class_suffix' => true,
~~~
开启后,你所有的类库都要统一加上你的目录名称(首字母大写)作为类库名的后缀(同时千万别忘了,文件名也要同时调整成和类名一样),例如:
~~~
<?php
namespace app\index\controller;
use think\Controller;
class HelloController extends Controller
{
// 显示欢迎页面
public function index()
{
return 'Hello,ThinkPHP!';
}
}
~~~
在你需要创建一个新控制器的时候,可以使用下面的命令:
~~~
php think make:controller index/TestController --plain
~~~
会自动生成一个控制器文件,位于:
~~~
application/index/controller/TestController.php
~~~
>[danger] 后面的练习如果没有特殊说明,都不开启应用类库后缀。