在PHP中调用子类的exit函数

时间:2015-01-13 19:36:25

标签: php parent-child exit

我有一个PHP类,我必须调用PHP header函数来显示一个网页。正如this post所指出的那样,标题后应跟exit回调。由于这种情况在我的课程中很常见,我在父类中定义了一个方法:

class ParentClass
{
    protected function header($url)
    {
        header('Location:'.$url);
        exit;
    }
} 

我想从子类中调用此方法:

class ChildClass extends ParentClass
{
    public function someFunc()
    {
        $this->header($some_url);
    }
} 

PHP documentationexit终止当前脚本。我的问题是:退出函数是否终止子脚本,即使它包含在父类中?

修改

在我的具体情况下,我使用的是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;
  }
}

由于这种情况在我的控制器中很常见,我更倾向于在header中定义BaseController方法而不是每次都输入

header('Location:someURL.html');
exit;

在我的OP中,我只想确保$this->header('admin.html');回调会终止当前login方法,即使它是在BaseController脚本中定义的。

希望现在有点清楚。

1 个答案:

答案 0 :(得分:1)

正如评论中已经描述的那样,退出将终止所有内容,即网页立即停止执行,包括清理功能和最后阻止。
因此,您应该非常谨慎地考虑使用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.
}

而不是调用exit方法,而应该实现清晰的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来显示响应用户,尝试添加一个响应,其中包含您要求显示的所有数据。这比在您的代码中到处都有print s(或echo s)更好。登记/> 使用响应对象,您的代码就可以只设置位置标头(如果它是重定向)或显示消息。因此,您不需要“杀死”网页的任何部分,并且在执行结束时它将终止。但同样:你可能很高兴在你的方法中使用exit调用(除非你遇到代码的任何问题(未提交的数据库事务,未更新的统计数据)(因为它在exit语句之后。Exit将完全终止您的脚本。