php 重定向 定义导入,我将如何使用PHP异常来定义重定向?

我一直被教导,在编程中使用异常可以使错误处理从引发错误的对象中抽象出来.从PHP manual来看,PHP似乎具有Exception类和ErrorException类,表明并非所有异常都必须是错误.因此,我想用它们来帮助页面重定向.

我想要一个硬重定向,该重定向将仅发送标头,而没有页面内容.触发此操作的最佳方法是什么?假设我有一个带有redirect()方法的Controller类.

该方法应如下所示:

class Controller {

public function redirect($path) {

throw new Exception($path, 301);

}

}

...

try {

$controller->redirect('http://domain.tld/redirected');

} catch (Exception $e) {

if ($e->getCode() == 301) {

header('Location: ' . $e->getMessage());

}

}

或像这样:

class Controller {

public function redirect($path) {

header('Location: ' . $path);

throw new Exception('The page is being redirected', 301);

}

}

...

try {

$controller->redirect('http://domain.tld/redirected');

} catch (Exception $e) {

if ($e->getCode() == 301) {

// Output nothing

}

}

还是应该创建一种新的异常类型,如下所示:

class RedirectException extends Exception {

protected $url;

public function __construct($url) {

parent::__construct('The redirects are coming!', 301);

$this->url = (string)$url;

}

public function getURL() {

return $this->url;

}

}

...

class Controller {

public function redirect($path) {

throw new RedirectException($path);

}

}

...

try {

$controller->redirect('http://domain.tld/redirected');

} catch (RedirectException $e) {

header('Location: ' . $e->getURL());

}

虽然我觉得所有这些方法都行得通,但没有一个人觉得我合适.最后一个似乎最接近,因为它清楚表明URL是必需的成员.但是,像这样的例外将仅用于一个目的.构建处理所有3XX,4XX和5XX状态代码的RequestException有意义吗?另外,该消息呢?这是否只是成为无关紧要的信息?

解决方法:

我也一直在玩这个游戏.我会分享我对此事的想法.

基本原理

问:当您可以使用标头和die语句轻松进行重定向时,为什么有人会使用异​​常进行重定向?

答:RFC2616所说的关于使用状态码301进行重定向:

Unless the request method was HEAD, the entity of the response SHOULD contain a short hypertext note with a hyperlink to the new URI(s).

因此,您实际上需要一些代码才能正确实现重定向.最好一次执行一次,使其易于重用.

问:但是您可以轻松实现重定向方法,就不需要Exception.

答:重定向时,如何知道以死方式杀死PHP脚本是“安全的”?也许堆栈中有一些代码正在等待您返回,因此它可以运行一些清理操作.通过抛出一个异常,堆栈中的代码可以捕获此异常并进行清理.

比较方式

您的示例#1和#3实际上是相同的,不同之处在于在#1中您正在滥用泛型Exception类.异常的名称应说明其功能(RedirectException),而不是属性(getCode()== 301),尤其是因为没有定义异常中的代码应与HTTP状态代码匹配的地方.另外,想要在情况#1中捕获重定向的代码不能简单地捕获(RedirectException $re),而需要检查getCode()的结果.这是不必要的开销.

#2和#3之间最重要的区别是您对接收异常的类有多少控制权.在#2中,您几乎说“重定向即将到来,这正在发生”,catch块没有可靠的方法来防止重定向发生.在#3中,您说“我想重定向,除非您有更好的主意”,但catch块将停止(“ catch”)重定向,只有在将异常进一步抛出堆栈之后,它才会发生.

选择哪个

这取决于您要在堆栈中赋予代码多少控制权.我个人认为堆栈中的代码应该能够取消重定向,这将使#3成为更好的选择.一个典型的用例是重定向到登录页面:设想一种方法,该方法将对当前用户执行某些操作,或者如果没有人登录,则重定向到登录页面.可以从未登录的页面调用该方法.要求用户已登录,但如果有的话,将提供其他功能.只是捕获异常比在方法周围编写代码要干净得多,仅是检查用户是否实际登录.

一些程序员可能会选择#2,因为他们认为如果某些代码启动了重定向,它期望这种重定向实际上会发生.允许拦截重定向并执行其他操作将使框架的可预测性降低.但是,我倾向于认为这就是例外.除非某些代码具有处理异常的方法,否则将发生与异常关联的操作.此操作通常是显示错误消息,但也可以是其他内容,例如重定向.

#3的示例实现

class RedirectException extends Exception {

const PERMANENT = 301;

const FOUND = 302;

const SEE_OTHER = 303;

const PROXY = 305;

const TEMPORARY = 307;

private static $messages = array(

301 => 'Moved Permanently',

302 => 'Found',

303 => 'See Other',

305 => 'Use Proxy',

307 => 'Temporary Redirect',

);

protected $url;

public function __construct($url, $code = 301, $message = NULL) {

parent::__construct($message

? (string)$message

: static::$messages[$code], (int)$code

);

if (strpos($url, '/') === 0) {

$this->url = static::getBaseURL() . $this->url;

}

$this->url = (string)$url;

}

public function getURL() {

return $this->url;

}

public function run() {

header('Location: ' . $this->url, true, $this->getCode());

}

}

结论

示例#1和#3几乎相同,但是#3是更好的设计. #2和#3都是很好的解决方案,具体取决于您的要求. Example#2将允许堆栈中的代码对重定向做出反应,但无法防止这种情况的发生. Example#3还将允许堆栈中的代码作出反应,但也将启用相同的代码以防止发生重定向.

标签:exception,http,php

来源: https://codeday.me/bug/20191208/2088476.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值