本文虽然没有解决实际性的问题,但是我学到了这些东西:
1.更加熟悉PHP这门语言
2.学到了一些在学基础语法时不知道的语法
3.PHP并没有我想象中的简单
1.提出疑问
虽然我已经创建好了项目,并且也跑通了,但是令我疑惑的是,我明明访问的是
http://127.0.0.1/ThinkphpDemo/public/
这个地址啊,为什么就出现这个画面了
![](https://img.haomeiwen.com/i2460738/50be936e69bb0c10.jpg)
带着疑问个纠结,我开始进行了代码的探索。
2.文档查询
我找到了这个,帮我介绍了项目目录:
tp5
├─application 应用目录
├─extend 扩展类库目录(可定义)
├─public 网站对外访问目录
├─runtime 运行时目录(可定义)
├─vendor 第三方类库目录(Composer)
├─thinkphp 框架核心目录
├─build.php 自动生成定义文件(参考)
├─composer.json Composer定义文件
├─LICENSE.txt 授权说明文件
├─README.md README 文件
├─think 命令行工具入口
根据访问地址,我运行的是public旗下的东西,public目录是网站对外访问目录,这个说明是啥意思,是指其他地方也可以通过这个地址访问到我本地的东西吗。
也许是这样吧,但是我只搭建了本地的服务器,所以别人访问不到。
3.public目录
首先来看看public目录里面有哪些东西吧
![](https://img.haomeiwen.com/i2460738/fc35733e4f8c7a9f.png)
好吧,就这些了,看不懂router.php里面是啥东西,用下面的地址也访问不出什么东西:
http://127.0.0.1/ThinkphpDemo/public/router.php
于是把焦点对准了index.php这个文件,尝试使用了一下的地址去访问:
http://127.0.0.1/ThinkphpDemo/public/index.php
没想到成功了,而且跟http://127.0.0.1/ThinkphpDemo/public访问的结果是一样的,居然使用这种地址可以直接访问到index.php文件,神奇哈。
4.主页内容
不过在index.php里面只有极少的代码:
// 定义应用目录
define('APP_PATH', __DIR__ . '/../application/');
// 加载框架引导文件
require __DIR__ . '/../thinkphp/start.php';
那真正的内容里面的数据是从哪里来的呢?漫无目的的找,肯定要找半天啦,全局搜索吧!
![](https://img.haomeiwen.com/i2460738/17fbca5881bfe486.png)
真被我给找到了,原来在另一个index.php目录下,在具体路径在这里application\index\controller\index.php
打开后,发现这里代码很少:
<?php
namespace app\index\controller;
class Index
{
public function index()
{
return '具体网页HTML代码';
}
}
我改改试试:
class Index
{
public function index()
{
return '你好';
}
}
运行结果:
![](https://img.haomeiwen.com/i2460738/47ce8b56f6009743.png)
5.代码追踪
哇!神奇,明明运行的是public目录下的代码,真正显示的居然是application\index\controller下的代码,不行,我需要知道原因。
来到public\index.php
// 定义应用目录
define('APP_PATH', __DIR__ . '/../application/');
// 加载框架引导文件
require __DIR__ . '/../thinkphp/start.php';
(在探索源码中学到的新知识点,我以这种形式记录下来)
发现新知识点,学基础语法的时候,没见过require这个东西,百度之后,这东西就是指定某个文件,然后运行他的意思
所以我来到了thinkphp/start.php这个文件下:
namespace think;
// ThinkPHP 引导文件
// 1. 加载基础文件
require __DIR__ . '/base.php';
// 2. 执行应用
App::run()->send();
我到底该看哪个呢?
聪明的添加了3行代码:
// ThinkPHP 引导文件
echo "hi1";
// 1. 加载基础文件
require __DIR__ . '/base.php';
echo "hi2";
// 2. 执行应用
App::run()->send();
echo "hi3";
这些运行后的执行结果是:
hi1hi2你好hi3
说明在h2和h3之间,那么我就来看App::run()->send();
这行代码吧,直接攻入send()方法中一探究竟。
public function send()
{
...
// 处理输出数据
$data = $this->getContent();
...
echo $data;
...
}
用着添加代码的手段发现了主要由这行代码显示了内容,所以$data
由是在哪里赋值的,继续跟踪吧!
进入getContent()方法看看:
public function getContent()
{
if (null == $this->content) {
$content = $this->output($this->data);
if (null !== $content && !is_string($content) && !is_numeric($content) && !is_callable([
$content,
'__toString',
])
) {
throw new \InvalidArgumentException(sprintf('variable type error: %s', gettype($content)));
}
$this->content = (string) $content;
}
return $this->content;
}
看来是类的属性$data啊,先跟踪下是在哪里赋值的,找了一圈发现是在构造方法里面
public function __construct($data = '', $code = 200, array $header = [], $options = [])
{
// 这里赋值
$this->data($data);
if (!empty($options)) {
$this->options = array_merge($this->options, $options);
}
$this->contentType($this->contentType, $this->charset);
$this->header = array_merge($this->header, $header);
$this->code = $code;
}
好吧,是要找谁调用了这个构造方法了是吧,我懂
empty:判断某个对象是否为空
public static function create($data = '', $type = '', $code = 200, array $header = [], $options = [])
{
$class = false !== strpos($type, '\\') ? $type : '\\think\\response\\' . ucfirst(strtolower($type));
if (class_exists($class)) {
$response = new $class($data, $code, $header, $options);
} else {
// 运行的是这里
$response = new static($data, $code, $header, $options);
}
return $response;
}
new static可以调用构造方法
来看看哪里调用的create方法,搜索了一下,发现thinkphp\library\think\App.php这里调用了create方法
public static function run(Request $request = null)
{
...
try {
...
// 这里赋值
$data = self::exec($dispatch, $config);
} catch (HttpResponseException $exception) {
$data = $exception->getResponse();
}
...
// 输出数据到客户端
if ($data instanceof Response) {
...
} elseif (!is_null($data)) {
...
$response = Response::create($data, $type);
} else {
$response = Response::create();
}
...
return $response;
}
看来要进self::exec($dispatch, $config);
里面看看了:
protected static function exec($dispatch, $config)
{
switch ($dispatch['type']) {
...
case 'module': // 模块/控制器/操作
$data = self::module(
$dispatch['module'],
$config,
isset($dispatch['convert']) ? $dispatch['convert'] : null
);
break;
...
}
return $data;
}
通过打印法得知$dispatch['type'] = 'module',那就进module方法中吧!
public static function module($result, $config, $convert = null)
{
...
return self::invokeMethod($call, $vars);
}
进invokeMethod里面
public static function invokeMethod($method, $vars = [])
{
if (is_array($method)) {
$class = is_object($method[0]) ? $method[0] : self::invokeClass($method[0]);
$reflect = new \ReflectionMethod($class, $method[1]);
} else {
// 静态方法
$reflect = new \ReflectionMethod($method);
}
$args = self::bindParams($reflect, $vars);
self::$debug && Log::record('[ RUN ] ' . $reflect->class . '->' . $reflect->name . '[ ' . $reflect->getFileName() . ' ]', 'info');
return $reflect->invokeArgs(isset($class) ? $class : null, $args);
}
new \类 如果当前给与路径没有找到,就全局找
再进invokeArgs方法(这里怎么看着像java的反射啊,硬着头皮看吧)
居然进了\php.jar!\stubs\Reflection\Reflection.php,这是PHP的源码吧!
public function invokeArgs ($object, array $args) {}
WTF?居然没有具体实现,这怎么办啊,找不动了啊,死这了,难受啊难受。
6.后话
跟踪源码都进PHP源码了,估计跟的太过了,肯定是方法不对,虽然此行并没有找到想要的结果,但是也不虚此行,在源码中学到了不少学基础语言的时候没有涉及到的知识点也不错了。
网友评论