Blogger Information
Blog 45
fans 3
comment 0
visits 45638
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
mvc控制器的访问与参数解析和API接口获取数据
残破的蛋蛋
Original
1659 people have browsed it

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试一下。

Correcting teacher:天蓬老师天蓬老师

Correction status:qualified

Teacher's comments:
Statement of this Website
The copyright of this blog article belongs to the blogger. Please specify the address when reprinting! If there is any infringement or violation of the law, please contact admin@php.cn Report processing!
All comments Speak rationally on civilized internet, please comply with News Comment Service Agreement
0 comments
Author's latest blog post