我有一个PHP类,我必须调用PHP header
函数来显示网页。正如这篇文章所指出的,标头后面应该跟exit
回调。由于这种情况在我的类中很常见,所以我在父类中定义了一个方法:
class ParentClass
{
protected function header($url)
{
header('Location:'.$url);
exit;
}
}
我想从儿童类调用此方法:
class ChildClass extends ParentClass
{
public function someFunc()
{
$this->header($some_url);
}
}
PHP 文档说exit
终止当前脚本。我的问题是:退出函数是否终止子脚本,即使它包含在父类中?
编辑
在我的特定情况下,我使用的是 MVC 设计模式,ChildClass
是一个控制器。在其中,有时我需要显示视图,有时我需要重定向到另一个 url。让我用一个实际的例子来解释它。
假设有一个带有登录部分的网站。向用户显示登录页面(未提交登录数据)时,登录控制器应显示登录视图。此视图包含一个具有类似 action="login.html"
的操作的窗体。提交数据时,将调用登录控制器并检查登录数据:如果登录成功,用户将被重定向到他的管理部分。
class UsersController extends BaseController
{
public function login()
{
try
{
if(isset($_POST['submit']))
{
// check login data, throw exception in case of error
// if success, redirect to admin section
$this->header('admin.html');
}
else
{
// show login view
}
}
catch(Exception $e)
{
// show login view (with error)
}
}
}
class BaseController
{
protected function header($url)
{
header('Location:'.$url);
exit;
}
}
由于这种情况在我的控制器中很常见,因此我更喜欢在BaseController
中定义一个header
方法,而不是每次都键入
header('Location:someURL.html');
exit;
在我的OP中,我只想确保$this->header('admin.html');
回调会终止当前的login
方法,即使它是在脚本中定义的BaseController
。
希望现在更清楚一点。
正如注释中已经描述的那样,exit 将终止所有内容,即网页立即停止执行,包括清理函数和最后阻止。
因此,您应该非常谨慎地考虑使用 exit,因为可能会发生很多事情:当您不使用自动提交时,数据不会写入数据库(除非您在调用 exit 之前提交数据)。默认情况下,PHP 的 MySQL 模块中不启用自动提交(据我所知)。
下面是一个示例:
class B extends A {
public function someFunc() {
# you might wanna use partent instead as
# pointed out by Ding in the comments, but
# maybe someFunc does more that just doing
# the redirect.
$this->header("http://google.com");
}
}
try {
print("Ok...");
$obj = new B();
$obj->someFunc();
print("Nahh..."); # doesn't get called/
} finally {
print("Cleaning up."); # doesn't get called, either.
}
与其调用退出方法,不如实现清晰的 MVC 设计模式。这是一个非常快速的示例:
<?php
class Response {
# use private here and use appropriate
# getters and setters.
public $status_code = 200;
public $content = "";
public $headers = array();
}
class HomeView extends View {
# called when a get request is made.
public function get() {
$response = new Response();
$response->content = "Hello world."
}
}
class RedirectionView {
public function get() {
$response = new Response();
$response->status_code = 301; # use 302 if moved only temporarily.
$response->headers["Location"] = "http://google.com";
}
}
function processRequest() {
# load appropriate view programatically
$view = new RedirectionView();
$response = $view->get();
http_response_code($response->status_code);
foreach ($response->headers as $headerName => $headerValue) {
header(sprintf("%s: %s", $headerName, $headerValue));
}
print($view->content)
}
?>
请注意,这不是真正的MVC设计模式(模型丢失了,但是,不清楚控制器是什么,但是,django(Pyhton框架)也使用了什么)。你可能想看看PHP MVC框架(快速的谷歌搜索就可以了)或实现你自己的框架(我的例子可能是一个好的开始)。
编辑 1:使用 exit
可能没问题(但我不会使用它,因为我认为这是不好的做法)。如果您能够编辑正在使用的设计方法,我会使您的 View BaseClass get/post 方法(或任何返回响应对象的方法。注意:如果您使用打印件向用户显示响应,请尝试添加包含请求需要显示的所有数据的响应。这比在代码中随处放置 print
s(或 echo
s)要好)。
使用响应对象,您的代码将能够只设置位置标头(如果是重定向)或显示消息。因此,您无需"杀死"网页的任何部分,它将在执行结束时终止。但同样:您可能最好在方法中使用exit
调用(除非您的代码遇到任何问题(未提交的数据库事务,未更新的统计数据(因为它在exit
语句之后)。 Exit
只会完全终止您的脚本。