类对象是按值传递的?

时间:2017-03-10 15:46:08

标签: php variables scope

我是PHP的新手。我想查看我使用过的变量的范围。特别是$model

$model = new LoginModel();
$controller = new LoginController($model);
$view = new LoginView($controller, $model);

下面附有我为登录而编写的代码。用户可以通过GET /login.php访问该页面,然后将表单提交到POST /login.php?action=login。在此过程中,LoginModel会相应地更新LoginController

我想使用我在页面执行的后续部分更新的$model。但是,我注意到$model是"重置"一旦呼叫从LoginController.login()返回。 我不确定是不是因为$model在我的情况下是按值传递的。或者,如果还有其他事情,我做错了,但我不知道。有谁可以启发我这个?

<?php
class LoginModel {
    public $username = "";
    public $password = "";
    public $message = "";
    public $loginSuccess = false;

    public function __construct() {

    }
}

class LoginView {
    private $model;
    private $controller;

    public function __construct($controller, $model) {
        $this->controller = $controller;
        $this->model = $model;
    }

    public function getUsernameField() {
        return $this->makeInput("text", "username", "");
    }

    public function getPasswordField() {
        return $this->makeInput("password", "password", "");
    }

    private function makeInput($type, $name, $value) {
        $html = "<input type=\"$type\" name=\"$name\" value=\"$value\" />";
        return $html;
    }
}

class LoginController {
    const HOME_URL = "http://localhost/";
    private $model;

    public function __construct($model) {
        $this->model = $model;
    }

    public function login() {
        $username = $_POST['username'];
        $password = $_POST['password'];

        if ($username === $password) { 
            $_SESSION['username'] = $username;

            $model->username = $username;
            $model->password = "";
            $model->message = "Hello, $username!";
            $model->loginSuccess = true;

            header("Refresh: 3; URL=" + LoginController::HOME_URL);
        } else {
            $model->message = "Sorry, you have entered an invalid username-password pair.";
            $model->loginSuccess = false;
        }
    }

    public function handleHttpPost() {
        if (isset($_GET['action'])) {
            if ($_GET['action'] === 'login') {
                $this->login();
            }
        } else {
            // invalid request.
            http_response_code(400);
            die();
        }
    }

    public function handleHttpGet() {
        if (isset($_GET['action'])) {
            // request for controller action
            // No controller actions for HTTP GET
        } else {
            // display login page
        }
    }

    public function redirectToHome() {
        header("Location: " + LoginController::HOME_URL);
        die();
    }
}


$model = new LoginModel();
$controller = new LoginController($model);
$view = new LoginView($controller, $model);

if (isset($_SESSION['username'])) {
    $controller->redirectToHome();
}

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $controller->handleHttpPost();
} else if ($_SERVER['REQUEST_METHOD'] === 'GET') {
    $controller->handleHttpGet();
}

?>

<html>

    <body>
        <?php if ($model->loginSuccess) { ?>
            <h1>Login Successful, Redirecting...</h1>
            <p><?= $model->message; ?></p>
        <?php
        } else { ?>
            <form action="login.php?action=login" method="POST">
                Username: <br />
                <?php echo $view->getUsernameField(); ?> <br/><br/>
                Password: <br />
                <?php echo $view->getPasswordField(); ?><br/><br/>
                <input type="submit" value="Log In"/>
            </form>
            <p><?= $model->message; ?></p>
        <?php
        }?>
    </body>
</html>

更新:已解决。感谢@RiggsFolly指出。

好吧,我弄错了$model

public function login() {
    ....
    $model->username = $username; //referenced the wrong variable
    $this->model->username = $username //should have done this.
}

另外,谢谢@Fred -ii - (抱歉,我离开了你)

public function login() {
    ....
    header("Refresh: 3; URL=" + LoginController::HOME_URL); //not the right way to concat
    header("Refresh: 3; URL=" . LoginController::HOME_URL); //should have been this.
}

1 个答案:

答案 0 :(得分:2)

只是一个简单的陈述

代表because $model was passed by value

我们在$model中有一个对象并将其传递给构造函数

$controller = new LoginController($model);

它将作为参考 $controller->model = $model

现在我们在控制器中有一个模型的参考。

如果您知道(如果可能,请允许,请说“是”):unset($controller->model);

你没有杀死$model个实例,你刚刚删除了之前设置的$model引用。

但现在反过来了:

#create an object
$model = new stdClass();

#create the holder
$b=new stdClass();
#bind the first obj
$b->model=$model;

#unset the first object
$model=null;
unset($model);

#oooh, what it is still there
print_r($b->model);

这里我们没有真正的unset($model),因为php知道稍后会使用该实例。所以php继续杀死$model和真实对象之间的引用,而不是$b->model和真实对象之间的引用。 在某种程度上,引用已经从一个ref指针移动到下一个。

关于

的最后一件事
  

默认情况下,函数参数按值传递(因此,如果函数中的参数值发生更改,则不会在函数外部更改)。

来自php documentaion。

在这里写passed by value时,它意味着它将如何运作。 但在实际过程中,它会在被操纵的那一刻复制。 所以它是passed by ref,但就像passed by value一样,只有对象在clone之前始终是引用。

在这个答案中保留最重要的信息:

  

首先,标题(“Refresh:3; URL =”+ LoginController :: HOME_URL);   你试图用一个+连接,在PHP中它是一个点   需要使用。你似乎是来自C背景,因此   错误。

感谢Fred -iii -