博客列表 >闭包(Closure)的创建和访问与自定义异常类(Exception)的使用- PHP培训十期线上班

闭包(Closure)的创建和访问与自定义异常类(Exception)的使用- PHP培训十期线上班

手机用户1576673622
手机用户1576673622原创
2020年02月20日 11:36:38856浏览

在php中,许多函数或方法的形参为callable类型, 这时,可以向这个参数传入具名函数或匿名函数。其中,匿名函数是php闭包的表示形式,为一个Closure类的实例。
下面,通过例子来演示闭包的创建和使用。

  1. //闭包类
  2. Closure {
  3. /*方法*/
  4. __construct ( void )
  5. public static Closure bind (Closure $closure , object $newthis [, mixed $newscope = 'static' ])
  6. public Closure bindTo (object $newthis [, mixed $newscope = 'static' ])
  7. }

一、创建闭包,与对象或类绑定来访问类成员

1. 创建闭包

  1. //文件名 closure\closureCreate.php
  2. namespace closure;
  3. use Closure;
  4. function closureCreate(string $name): Closure
  5. {
  6. //创建闭包
  7. return function (string $var) use ($name) {
  8. return sprintf('%s%s',$name,$var);
  9. };
  10. }
  11. $closure = closureCreate('php中文网');
  12. //使用闭包
  13. echo $closure('欢迎您!');
结果

2. 将闭包与对象或类绑定来访问类成员

  1. <?php
  2. //文件 closure\closureAccess.php
  3. namespace closure;
  4. use Closure;
  5. class closureAccess
  6. {
  7. public $publicVar = '';
  8. public static $staticVar = '';
  9. private $privateVar = '';
  10. private static $privateStaVar = '';
  11. protected $protectedVar = '';
  12. protected static $protectedStaVar = '';
  13. //取不存在的值时
  14. public function __get(string $name): string
  15. {
  16. //如果非静态
  17. if (isset($this->$name)) {
  18. return $this->$name;
  19. }
  20. //如果静态
  21. if (isset(static::${$name})) {
  22. return static::${$name};
  23. }
  24. }
  25. //设置不存在的值时
  26. public function __set(string $name, $value): void
  27. {
  28. //如果非静态
  29. if (isset($this->$name)) {
  30. $this->$name = $value;
  31. }
  32. //如果静态
  33. if (isset(static::${$name})) {
  34. static::${$name} = $value;
  35. }
  36. }
  37. //把对象当字符访问时
  38. public function __toString(): string
  39. {
  40. return <<<DOC
  41. publicvar = {$this->publicVar}</br>
  42. staticVar = {$this->staticVar}</br>
  43. privateVar = {$this->privateVar}</br>
  44. privateStaVar = {$this->privateStaVar}</br>
  45. protectedVar = {$this->protectedVar}</br>
  46. protectedStaVar = {$this->protectedStaVar}</br>
  47. DOC;
  48. }
  49. }
  50. //匿名函数,闭包
  51. $setter = function (string $publicVar, string $staticVar, string $privateVar, string $privateStaVar, string $protectedVar, string $protectedStaVar): void
  52. {
  53. //绑定 public
  54. $this->publicVar = $publicVar;
  55. //绑定 public static变量
  56. static::$staticVar = $staticVar;
  57. //绑定private变量
  58. $this->privateVar = $privateVar;
  59. //绑定private static变量
  60. $this->privateStaVar = $privateStaVar;
  61. //绑定protected 变量
  62. $this->protectedVar = $protectedVar;
  63. //绑定protected static 变量
  64. $this->protectedStaVar = $protectedStaVar;
  65. };
  66. $closureAccess = new closureAccess();
  67. //既有实例也有类,双绑定
  68. // $closure=$setter->bindTo($closureAccess, closureAccess::class);
  69. $closure = Closure::bind($setter, $closureAccess, closureAccess::class);
  70. $closure('a', 'b', 'c', 'd', 'e', 'f');
  71. echo $closureAccess;
结果

编程过程中,常出现很多的错误和异常,php有专门处理错误和异常的类(Exception类),可自定义该类的__toString()方法,自定义错误或异常的输出.

二、创建自定义异常类,实现用户登录与验证流程的异常处理

1. 自定义异常类
  1. //文件src\login\LoginException.php;
  2. namespace src\login;
  3. use Exception;
  4. class LoginException extends Exception
  5. {
  6. public function __construct($message,$previous)
  7. {
  8. parent :: __construct($message, $previous);
  9. }
  10. public function __toString(): string
  11. {
  12. return <<<DOC
  13. <table border="1" cellsapcing="0" cellpadding="5">
  14. <tr bgcolor="wheat">
  15. <th>错误信息</th>
  16. <th>代码</th>
  17. <th>文件</th>
  18. <th>行号</th>
  19. </tr>
  20. <tr>
  21. <td>$this->message</td>
  22. <td>$this->code</td>
  23. <td>$this->file</td>
  24. <td>$this->line</td>
  25. </tr>
  26. </table>
  27. DOC;
  28. }
  29. }
2.用户登录
  1. <?php
  2. //文件 src\login\LoginView.php
  3. namespace src\login;
  4. class LoginView
  5. {
  6. private $action;
  7. private $checkAction;
  8. private $checkStyle;
  9. public function __construct(string $action)
  10. {
  11. $this->action = $action;
  12. }
  13. //设置验证请求的内容: ....?action=login;
  14. public function setCheckStyle(string $checkAction, string $checkStyle): void
  15. {
  16. $this->checkAction = $checkAction;
  17. $this->checkStyle = $checkStyle;
  18. }
  19. public function loginSimple(): string
  20. {
  21. return <<<DOC
  22. <!DOCTYPE html>
  23. <html lang="en">
  24. <head>
  25. <meta charset="UTF-8">
  26. <title>Document</title>
  27. </head>
  28. <body>
  29. <h3>用户登录</h3>
  30. <form action="{$this->action}?{$this->checkAction}={$this->checkStyle}" method="post">
  31. <div>
  32. <label for="name">用户名</label>
  33. <input type="text" id='name' name='name'>
  34. </div>
  35. <div>
  36. <label for="pssword">密码</label>
  37. <input type="password" id='password' name='password'>
  38. </div>
  39. <button>提交</button>
  40. </form>
  41. </body>
  42. </html>
  43. DOC;
  44. }
  45. }
3.数据库准备
  1. <?php
  2. //文件 src\login\LoginModel.php;
  3. namespace src\login;
  4. use mysqli;
  5. require 'LoginAutoload.php';
  6. class LoginModel
  7. {
  8. private $mysqli;
  9. public function __construct(string $host, string $user, string $password, string $dbname)
  10. {
  11. $this->mysqli = new mysqli($host, $user, $password, $dbname);
  12. }
  13. public function __set(string $name, $value)
  14. {
  15. $this->{$name} = $value;
  16. }
  17. //从数据库查询数据
  18. public function select()
  19. {
  20. try {
  21. $sql = 'SELECT ' . $this->fields . ' FROM ' . $this->table . (($this->condition) ? ' WHERE ' . $this->condition : NULL) . ';';
  22. //处理查询异常
  23. if (!$this->mysqli->query($sql)) throw new LoginException($sql . '<br>查询语句有误', 303);
  24. $result = $this->mysqli->query($sql);
  25. return $result->fetch_all(MYSQLI_ASSOC);
  26. } catch (LoginException $e) {
  27. echo $e;
  28. }
  29. }
  30. }
4.登录验证
  1. <?php
  2. //文件 src\login\LoginControl;
  3. namespace src\login;
  4. require 'LoginAutoload.php';
  5. class LoginControl
  6. {
  7. private $loginModel;
  8. private $callback;
  9. public function __construct(LoginModel $loginModel)
  10. {
  11. $this->loginModel = $loginModel;
  12. }
  13. //设置回调函数用于验证
  14. public function setCallback(callable $callback): void
  15. {
  16. $this->callback = $callback;
  17. }
  18. //验证来源
  19. public function checkUrl(): bool
  20. {
  21. $currentUrl = basename(filter_input(INPUT_SERVER, 'SCRIPT_NAME'));
  22. //设置查询条件
  23. $this->loginModel->condition = $this->loginModel->fields . '=\'' . $currentUrl . '\'';
  24. try {
  25. if (!($this->loginModel->select())) throw new LoginException('非法来源', 101);
  26. echo '合法来源';
  27. return true;
  28. } catch (LoginException $e) {
  29. echo $e;
  30. return false;
  31. }
  32. }
  33. //检查请求内容
  34. public function checkAction($checkAction): bool
  35. {
  36. $action = filter_input(INPUT_GET, $checkAction, FILTER_SANITIZE_STRING);
  37. //设置查询条件
  38. $this->loginModel->condition = $this->loginModel->fields . '=\'' . strtolower($action) . '\'';
  39. //如果请求内容不匹配,提示
  40. try {
  41. if (!($this->loginModel->select())) throw new LoginException('<br>无需验证', 305);
  42. echo '<br>须验证:' . $checkAction;
  43. return true;
  44. } catch (LoginException $e) {
  45. echo '<br>' . $e->getMessage();
  46. return false;
  47. }
  48. }
  49. //验证POST请求
  50. public function checkPost(): bool
  51. {
  52. $check = function ($res) {
  53. try {
  54. //如果验证条件有异常
  55. if (!$res) throw new LoginException('验证不通过', 102);
  56. //设置cookie;
  57. setcookie('user', $res);
  58. exit('<script>alert("验证通过");</script>');
  59. } catch (LoginException $e) {
  60. echo $e;
  61. exit('<script>alert("' . $e->getMessage() . '");</script>');
  62. }
  63. };
  64. //请求是否合法
  65. try {
  66. if (!(filter_input(INPUT_SERVER, 'REQUEST_METHOD') === 'POST')) throw new LoginException('<br>非法请求', 101);
  67. echo "<br>合法请求";
  68. $check(call_user_func_array($this->callback, [$this->loginModel]));
  69. return true;
  70. } catch (LoginException $e) {
  71. echo $e;
  72. return false;
  73. }
  74. }
  75. }
  76. //数据库
  77. $localhost = 'db.io';
  78. $user = 'root';
  79. $password = 'root';
  80. $dbname = 'phpedu';
  81. $loginModel = new LoginModel($localhost, $user, $password, $dbname);
  82. $loginModel->fields = '`url`';
  83. $loginModel->table = '`urls`';
  84. $loginControl = new LoginControl($loginModel);
  85. //验证来源是否合法
  86. //SELECT `url` FROM `urls` WHERE `url`='LoginControl.php';
  87. if (!$loginControl->checkUrl()) return;
  88. //检查是否需要验证login
  89. //LoginContro.php?action=login
  90. $loginModel->fields = '`action`';
  91. $loginModel->table = '`actions`';
  92. if (!$loginControl->checkAction('action')) return;
  93. //验证`name`和`password`;
  94. $loginModel->fields = '`name`, `password`';
  95. //验证`name`和`password`是否在数据库中
  96. //传入验证内容的匿名函数,
  97. $loginControl->setCallback(function (LoginModel $mysqli)
  98. {
  99. $name = filter_input(INPUT_POST, 'name');
  100. $password = sha1(filter_input(INPUT_POST, 'password'));
  101. //查找 SELECT `password` FROM `users` WHERE `name`='小龙女';
  102. $mysqli->fields = "`password`";
  103. $mysqli->condition = "`name`='{$name}'";
  104. $mysqli->table = '`users`';
  105. //处理查询异常
  106. try {
  107. if (!$mysqli->select()) throw new LoginException('查询失败', 305);
  108. foreach ($mysqli->select() as $val) {
  109. if ($val['password'] === $password) {
  110. return $name;
  111. }
  112. }
  113. } catch (LoginException $e) {
  114. echo $e;
  115. }
  116. });
  117. //验证POST请求,
  118. //如果`name`和`password`在数据库中,则setcookie,否则提示验证失败
  119. $loginControl->checkPost();
5.自动加载
  1. <?php
  2. //文件login/LoginAutoload.php
  3. namespace src\login;
  4. spl_autoload_register(function($class)
  5. {
  6. $prefix=__DIR__;
  7. $arr=explode("\\",$class);
  8. $file=$prefix."\\". $arr[count($arr)-1] . '.php';
  9. $file = str_replace("\\", DIRECTORY_SEPARATOR, $file);
  10. file_exists($file) ? require $file : "文件不存在,加载失败";
  11. });
6.调用
  1. <?php
  2. //文件 src\login\LoginMain.php;
  3. namespace src\login;
  4. require 'LoginAutoload.php';
  5. $loginView=new LoginView('LoginControl.php');
  6. $loginView->setCheckStyle('action','login');
  7. echo $loginView->loginSimple();
用到的数据库phpedu3个表: users, urls, actions
1.users

2.urls

3.actions

结果
1. 密码错误时



2. 密码正确时



3. 用户不存在时



总结

1.闭包:闭包可以将一个执行环境(父级中的变量/状态)封闭到匿名函数中;常用于作为函数/方法的回调参数。闭包是一个对象,是Closure类的实例;可以把外部数据封闭到闭包中保存,也可以将闭包绑定到对象/类上,实现对属性的更新操作;
2.异常:与错误机制相比,异常处理机制主动抛出,更加主动和灵活;有时异常并不一定发生了错误,所以异常应用范围更广;通常并不会直接使用系统的异常类,而是自定义一个异常类

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