批改状态:合格
老师批语:几乎所有的语言都支持匿名函数, 但并不是所有的匿名函数都是闭包, 闭包的形成有一定的条件, 这个要注意
在php中,许多函数或方法的形参为callable类型, 这时,可以向这个参数传入具名函数或匿名函数。其中,匿名函数是php闭包的表示形式,为一个Closure类的实例。
下面,通过例子来演示闭包的创建和使用。
//闭包类Closure {/*方法*/__construct ( void )public static Closure bind (Closure $closure , object $newthis [, mixed $newscope = 'static' ])public Closure bindTo (object $newthis [, mixed $newscope = 'static' ])}
//文件名 closure\closureCreate.phpnamespace closure;use Closure;function closureCreate(string $name): Closure{//创建闭包return function (string $var) use ($name) {return sprintf('%s%s',$name,$var);};}$closure = closureCreate('php中文网');//使用闭包echo $closure('欢迎您!');

<?php//文件 closure\closureAccess.phpnamespace closure;use Closure;class closureAccess{public $publicVar = '';public static $staticVar = '';private $privateVar = '';private static $privateStaVar = '';protected $protectedVar = '';protected static $protectedStaVar = '';//取不存在的值时public function __get(string $name): string{//如果非静态if (isset($this->$name)) {return $this->$name;}//如果静态if (isset(static::${$name})) {return static::${$name};}}//设置不存在的值时public function __set(string $name, $value): void{//如果非静态if (isset($this->$name)) {$this->$name = $value;}//如果静态if (isset(static::${$name})) {static::${$name} = $value;}}//把对象当字符访问时public function __toString(): string{return <<<DOCpublicvar = {$this->publicVar}</br>staticVar = {$this->staticVar}</br>privateVar = {$this->privateVar}</br>privateStaVar = {$this->privateStaVar}</br>protectedVar = {$this->protectedVar}</br>protectedStaVar = {$this->protectedStaVar}</br>DOC;}}//匿名函数,闭包$setter = function (string $publicVar, string $staticVar, string $privateVar, string $privateStaVar, string $protectedVar, string $protectedStaVar): void{//绑定 public$this->publicVar = $publicVar;//绑定 public static变量static::$staticVar = $staticVar;//绑定private变量$this->privateVar = $privateVar;//绑定private static变量$this->privateStaVar = $privateStaVar;//绑定protected 变量$this->protectedVar = $protectedVar;//绑定protected static 变量$this->protectedStaVar = $protectedStaVar;};$closureAccess = new closureAccess();//既有实例也有类,双绑定// $closure=$setter->bindTo($closureAccess, closureAccess::class);$closure = Closure::bind($setter, $closureAccess, closureAccess::class);$closure('a', 'b', 'c', 'd', 'e', 'f');echo $closureAccess;

编程过程中,常出现很多的错误和异常,php有专门处理错误和异常的类(Exception类),可自定义该类的__toString()方法,自定义错误或异常的输出.
//文件src\login\LoginException.php;namespace src\login;use Exception;class LoginException extends Exception{public function __construct($message,$previous){parent :: __construct($message, $previous);}public function __toString(): string{return <<<DOC<table border="1" cellsapcing="0" cellpadding="5"><tr bgcolor="wheat"><th>错误信息</th><th>代码</th><th>文件</th><th>行号</th></tr><tr><td>$this->message</td><td>$this->code</td><td>$this->file</td><td>$this->line</td></tr></table>DOC;}}
<?php//文件 src\login\LoginView.phpnamespace src\login;class LoginView{private $action;private $checkAction;private $checkStyle;public function __construct(string $action){$this->action = $action;}//设置验证请求的内容: ....?action=login;public function setCheckStyle(string $checkAction, string $checkStyle): void{$this->checkAction = $checkAction;$this->checkStyle = $checkStyle;}public function loginSimple(): string{return <<<DOC<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>Document</title></head><body><h3>用户登录</h3><form action="{$this->action}?{$this->checkAction}={$this->checkStyle}" method="post"><div><label for="name">用户名</label><input type="text" id='name' name='name'></div><div><label for="pssword">密码</label><input type="password" id='password' name='password'></div><button>提交</button></form></body></html>DOC;}}
<?php//文件 src\login\LoginModel.php;namespace src\login;use mysqli;require 'LoginAutoload.php';class LoginModel{private $mysqli;public function __construct(string $host, string $user, string $password, string $dbname){$this->mysqli = new mysqli($host, $user, $password, $dbname);}public function __set(string $name, $value){$this->{$name} = $value;}//从数据库查询数据public function select(){try {$sql = 'SELECT ' . $this->fields . ' FROM ' . $this->table . (($this->condition) ? ' WHERE ' . $this->condition : NULL) . ';';//处理查询异常if (!$this->mysqli->query($sql)) throw new LoginException($sql . '<br>查询语句有误', 303);$result = $this->mysqli->query($sql);return $result->fetch_all(MYSQLI_ASSOC);} catch (LoginException $e) {echo $e;}}}
<?php//文件 src\login\LoginControl;namespace src\login;require 'LoginAutoload.php';class LoginControl{private $loginModel;private $callback;public function __construct(LoginModel $loginModel){$this->loginModel = $loginModel;}//设置回调函数用于验证public function setCallback(callable $callback): void{$this->callback = $callback;}//验证来源public function checkUrl(): bool{$currentUrl = basename(filter_input(INPUT_SERVER, 'SCRIPT_NAME'));//设置查询条件$this->loginModel->condition = $this->loginModel->fields . '=\'' . $currentUrl . '\'';try {if (!($this->loginModel->select())) throw new LoginException('非法来源', 101);echo '合法来源';return true;} catch (LoginException $e) {echo $e;return false;}}//检查请求内容public function checkAction($checkAction): bool{$action = filter_input(INPUT_GET, $checkAction, FILTER_SANITIZE_STRING);//设置查询条件$this->loginModel->condition = $this->loginModel->fields . '=\'' . strtolower($action) . '\'';//如果请求内容不匹配,提示try {if (!($this->loginModel->select())) throw new LoginException('<br>无需验证', 305);echo '<br>须验证:' . $checkAction;return true;} catch (LoginException $e) {echo '<br>' . $e->getMessage();return false;}}//验证POST请求public function checkPost(): bool{$check = function ($res) {try {//如果验证条件有异常if (!$res) throw new LoginException('验证不通过', 102);//设置cookie;setcookie('user', $res);exit('<script>alert("验证通过");</script>');} catch (LoginException $e) {echo $e;exit('<script>alert("' . $e->getMessage() . '");</script>');}};//请求是否合法try {if (!(filter_input(INPUT_SERVER, 'REQUEST_METHOD') === 'POST')) throw new LoginException('<br>非法请求', 101);echo "<br>合法请求";$check(call_user_func_array($this->callback, [$this->loginModel]));return true;} catch (LoginException $e) {echo $e;return false;}}}//数据库$localhost = 'db.io';$user = 'root';$password = 'root';$dbname = 'phpedu';$loginModel = new LoginModel($localhost, $user, $password, $dbname);$loginModel->fields = '`url`';$loginModel->table = '`urls`';$loginControl = new LoginControl($loginModel);//验证来源是否合法//SELECT `url` FROM `urls` WHERE `url`='LoginControl.php';if (!$loginControl->checkUrl()) return;//检查是否需要验证login//LoginContro.php?action=login$loginModel->fields = '`action`';$loginModel->table = '`actions`';if (!$loginControl->checkAction('action')) return;//验证`name`和`password`;$loginModel->fields = '`name`, `password`';//验证`name`和`password`是否在数据库中//传入验证内容的匿名函数,$loginControl->setCallback(function (LoginModel $mysqli){$name = filter_input(INPUT_POST, 'name');$password = sha1(filter_input(INPUT_POST, 'password'));//查找 SELECT `password` FROM `users` WHERE `name`='小龙女';$mysqli->fields = "`password`";$mysqli->condition = "`name`='{$name}'";$mysqli->table = '`users`';//处理查询异常try {if (!$mysqli->select()) throw new LoginException('查询失败', 305);foreach ($mysqli->select() as $val) {if ($val['password'] === $password) {return $name;}}} catch (LoginException $e) {echo $e;}});//验证POST请求,//如果`name`和`password`在数据库中,则setcookie,否则提示验证失败$loginControl->checkPost();
<?php//文件login/LoginAutoload.phpnamespace src\login;spl_autoload_register(function($class){$prefix=__DIR__;$arr=explode("\\",$class);$file=$prefix."\\". $arr[count($arr)-1] . '.php';$file = str_replace("\\", DIRECTORY_SEPARATOR, $file);file_exists($file) ? require $file : "文件不存在,加载失败";});
<?php//文件 src\login\LoginMain.php;namespace src\login;require 'LoginAutoload.php';$loginView=new LoginView('LoginControl.php');$loginView->setCheckStyle('action','login');echo $loginView->loginSimple();
phpedu3个表: users, urls, actions











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