Blogger Information
Blog 29
fans 0
comment 0
visits 19745
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
闭包(Closure)的创建和访问与自定义异常类(Exception)的使用- PHP培训十期线上班
手机用户1576673622
Original
853 people have browsed it

在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.异常:与错误机制相比,异常处理机制主动抛出,更加主动和灵活;有时异常并不一定发生了错误,所以异常应用范围更广;通常并不会直接使用系统的异常类,而是自定义一个异常类

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