博客列表 >mvc控制器的访问与参数解析和API接口获取数据

mvc控制器的访问与参数解析和API接口获取数据

残破的蛋蛋
残破的蛋蛋原创
2021年03月07日 15:27:171658浏览

mvc控制器的访问与参数解析和API接口获取数据

一、控制器访问与参数解析

我们在使用框架,诸如 ThinkPHPLaravel时,访问一个页面,例如:http://localhost/idnex.php/user/admin/id/1,这样就可以找到用户名(user)为admin,id为1的用户了。这是什么原理呢?这个就是通过PATHINFO的方式来进行的参数解析。框架是MVC架构,我们也知道,框架在运行过程中,我们实际上访问的是控制器的方法,因此,url地址最终肯定都要定位到一个控制器方法中。

  • 案例:假设当前demo1.php脚本当成框架的入口文件(类似于TP中的index.php入口文件)。即访问地址是:http://localhost:8888/PHP/20210305/demo1.php?controller=user&action=show

  • 控制器类

  1. class UserController
  2. {
  3. public function show() : string
  4. {
  5. return "Hello, World!";
  6. }
  7. }
  • 解析控制器
  1. // 通过url地址获取controller和action参数
  2. $controller = ucfirst($_GET['controller']) . 'Controller';
  3. $action = $_GET['action'];
  4. // 实例化控制器类,调用show方法
  5. echo (new $controller)->$action();

但是上述通过查询字符串的格式的地址,对于搜索引擎不友好,可以用PATHINFO来优化,地址可以变更成为:http://localhost:8888/PHP/20210305/demo1.php/controller/user/action/show

  1. // 获取PATHINFO路径
  2. $pathinfo = $_SERVER['PATH_INFO'];
  3. // 将PATHINFO路径以“/”为分隔符,切割成一个数组
  4. $queryArr = explode('/', ltrim($pathinfo, '/'));
  5. $controller = ucfirst(array_shift($queryArr)) . 'Controller';
  6. $action = array_shift($queryArr);
  7. echo (new $controller)->$action();

如果,我们要在PATHINFO路径中传参又该如何解析呢?下面,我把上述的访问地址改造一下,修改成带参数的PATHINFO路径:http://localhost:8888/PHP/20210305/demo1.php/user/show/id/10/name/admin

  • 控制器类
  1. namespace mvc;
  2. class UserController
  3. {
  4. public function show(int $id, string $name) : string
  5. {
  6. return "Hello, {$name}! => {$id}";
  7. }
  8. }

根据上述访问地址,先拿到PATHINFO路径,以“/”为分隔符,将其切割成一个数组,并过滤掉数组中键值为空的元素:

  1. $pathinfo = array_filter(explode('/', $_SERVER['PATH_INFO']));
  • 结果图

解析pathinfo参数

然后根据上面拿到的结果,生成控制器和方法:

  1. // 生成控制器
  2. $controller = __NAMESPACE__ . '\\' . array_shift($pathinfo) . 'Controller';
  3. // 生成方法
  4. $action = array_shift($pathinfo);

生成了控制器和方法之后,此时就可以将参数从PATHINFO中解析出来了,我们现在先打印一下目前$pathinfo的值:

  1. printf('<pre>%s</pre>', print_r($pathinfo, true));
  • 结果

打印$pathinfo的值

从上面的结果可以看出,数组中的元素,两两为一组,就是PATHINFO路径中传递的参数值,可以用一个循环将参数和其值保存起来:

  1. // 创建一个空数组保存参数
  2. $params = [];
  3. for ($i=0; $i < count($pathinfo); $i += 2) {
  4. $params[$pathinfo[$i]] = $pathinfo[$i + 1];
  5. }

同时,我们需要考虑的一个问题是:用户有可能在传参的时候传了一个空值,如果我们不处理的话就会造成错误:

处理参数值为空的情况

  1. // 创建一个空数组保存参数
  2. $params = [];
  3. for ($i=0; $i < count($pathinfo); $i += 2) {
  4. // 判断当前循环的$i+1的值是否存在
  5. if (isset($pathinfo[$i + 1])) {
  6. $params[$pathinfo[$i]] = $pathinfo[$i + 1];
  7. }
  8. }
  9. // 异步调用
  10. echo call_user_func_array([(new $controller), $action], $params);

这样就不会存在传递的参数中有空值而报错的情况了。

  • 结果

Hello, admin! => 10

二、API接口获取数据演示

API接口使用的是聚合数据提供的免费API,该案例主要是为了研究如何调用第三方接口获取一些数据。我找了一个成语接龙的免费接口做测试案例,下面分享一下我写的代码。

  • 后端代码
  1. declare(strict_types = 1);
  2. namespace homework\api;
  3. use Exception;
  4. class API
  5. {
  6. /**
  7. * 请求api
  8. *
  9. * @var string
  10. */
  11. private $baseUrl = 'http://apis.juhe.cn/idiomJie/query';
  12. /**
  13. * 请求参数数组
  14. *
  15. * @var array
  16. */
  17. public $params = [];
  18. /**
  19. * 初始化参数
  20. *
  21. * @param array $params
  22. */
  23. public function __construct(array $params = [])
  24. {
  25. $this->params = $params;
  26. }
  27. /**
  28. * 从API获取数据
  29. *
  30. * @return string
  31. */
  32. public function getQueryData() : string
  33. {
  34. // 构造查询参数
  35. $query = http_build_query($this->params);
  36. // 完整的查询API地址
  37. $url = $this->baseUrl.'?'.$query;
  38. // echo $url;
  39. // cURL:发起一个http请求
  40. return $this->curl_get($url);
  41. }
  42. /**
  43. * 创建cURL请求
  44. *
  45. * @param string url地址
  46. * @return string
  47. */
  48. public function curl_get(string $url) : string
  49. {
  50. // 初始化cURL
  51. $ch = curl_init();
  52. // 设置请求的url完整地址
  53. curl_setopt($ch, CURLOPT_URL, $url);
  54. // 设置请求类型
  55. curl_setopt($ch, CURLOPT_HTTPGET, true);
  56. // 设置hedaer头信息,这里不需要就去掉
  57. curl_setopt($ch, CURLOPT_HEADER, false);
  58. // 默认是浏览器输出,只返回不输出
  59. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  60. // 执行curl
  61. $data = curl_exec($ch);
  62. if ($data) {
  63. curl_close($ch);
  64. return $data;
  65. } else {
  66. $errno = curl_errno($ch);
  67. curl_close($ch);
  68. throw new Exception("curl出错,错误码:$errno");
  69. }
  70. }
  71. }
  72. $api = new API(['key' => '6a2fb6390f349aec8661a7e9ddae141c', 'wd' => $_REQUEST['val']]);
  73. echo $api->getQueryData();
  • 前端代码
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
  6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  7. <title>API接口请求数据示例</title>
  8. <style>
  9. * {
  10. box-sizing: border-box;
  11. }
  12. .form {
  13. width: 40rem;
  14. height: 3rem;
  15. margin: 5rem 10rem 0;
  16. overflow: hidden;
  17. border-radius: 0;
  18. }
  19. form {
  20. width: 40rem;
  21. height: 3rem;
  22. position: relative;
  23. }
  24. form input {
  25. width: 34rem;
  26. height: 3rem;
  27. /* border-radius: 10px; */
  28. border-top-left-radius: 10px;
  29. border-bottom-left-radius: 10px;
  30. outline: none;
  31. border: none;
  32. font-size: 1.5rem;
  33. text-indent: .5rem;
  34. border: 2px solid #c4c7ce;
  35. transition: all .5s;
  36. }
  37. form input:hover {
  38. transition: all .5s;
  39. border-color: #4e6ef2;
  40. }
  41. form button {
  42. width: 6rem;
  43. height: 3rem;
  44. border-top-right-radius: 10px;
  45. border-bottom-right-radius: 10px;
  46. background-color: #4e6ef2;
  47. font-size: 1.1rem;
  48. border: 2px solid #4e6ef2;
  49. color: #fff;
  50. position: absolute;
  51. right: 0;
  52. top: 0;
  53. outline: none;
  54. cursor: pointer;
  55. }
  56. ul, li {
  57. list-style: none;
  58. margin: 0;
  59. padding: 0;
  60. }
  61. .content {
  62. width: calc(100% - 6rem);
  63. border: 2px solid #4e6ef2;
  64. border-top-width: 0;
  65. height: 25rem;
  66. padding: 1rem 0 0 1rem;
  67. }
  68. ul {
  69. width: 100%;
  70. height: calc(100% - 1rem);
  71. background-color: #fff;
  72. overflow-y: scroll;
  73. }
  74. ul li {
  75. width: 100%;
  76. line-height: 1.6rem;
  77. }
  78. </style>
  79. </head>
  80. <body>
  81. <div class="form">
  82. <form method="get" name="form" onsubmit="return false;">
  83. <input type="text" value="" placeholder="输入成语的最后一个字查找相关成语">
  84. <button type="button">查找一下</button>
  85. </form>
  86. <div class="content">
  87. <ul></ul>
  88. </div>
  89. </div>
  90. <script>
  91. const form = document.querySelector('.form');
  92. const btn = document.querySelector('button');
  93. const ul = document.querySelector('ul');
  94. const input = document.querySelector('input');
  95. // 点击搜索按钮执行ajax
  96. btn.onclick = ev => {
  97. ev.preventDefault();
  98. getData();
  99. ev.stopPropagation();
  100. };
  101. // 点击回车键执行ajax
  102. input.addEventListener("keydown", ev => {
  103. console.log(ev);
  104. if (ev.keyCode === 13) {
  105. getData();
  106. }
  107. ev.stopPropagation();
  108. });
  109. input.addEventListener('input', ev => {
  110. console.log(ev);
  111. if(ev.target.value === '') {
  112. ul.innerHTML = null;
  113. form.style.height = '3rem';
  114. input.style.borderColor = '#c4c7ce';
  115. input.style.borderTopLeftRadius = '10px';
  116. input.style.borderBottomLeftRadius = '10px';
  117. }
  118. });
  119. /**
  120. * ajax获取数据
  121. *
  122. * @return void
  123. */
  124. function getData() {
  125. // 输入框里的内容
  126. const val = input.value;
  127. // 1.创建xhr对象
  128. let xhr = new XMLHttpRequest;
  129. // 2.配置xhr请求参数
  130. xhr.open('get', `api.php?val=${val}`);
  131. xhr.responseType = 'json';
  132. // 3.响应xhr请求
  133. // 成功
  134. xhr.onload = () => {
  135. form.style.height = 'auto';
  136. input.style.borderColor = '#4e6ef2';
  137. input.style.borderRadius = '0';
  138. console.log(xhr.response);
  139. const result = xhr.response;
  140. const frag = document.createDocumentFragment();
  141. for (let i = 0; i < result.result.total_count; i++) {
  142. const li = document.createElement('li');
  143. li.textContent = result.result.data[i];
  144. frag.appendChild(li);
  145. }
  146. ul.appendChild(frag);
  147. }
  148. // 失败
  149. xhr.onerror = () => {
  150. console.log('xhr error...');
  151. }
  152. // 4.发送xhr
  153. xhr.send(null);
  154. }
  155. </script>
  156. </body>
  157. </html>
  • 效果图

API请求数据

心得总结:其实大部分的第三方API,一般都给的有文档,我们只需要按照文档来进行操作即可,有的还给出的有demo案例,如果真的不会可以先跑一遍别人的demo试一下。

声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议