简体   繁体   中英

PHP Factory Class Inheritance Issue

I have worked on my own factory class that instantiates dependencies and passes through constructs when a dependency is set/requested. If the dependency is cached ( Has already been instantiated by another class ) i pass that class instance instead of instantiating all over again ( mainly used for db connection ). The issue i am having at the moment is as follows.

** To avoid a large question & save reading time i am attempting to illustrate the issue as simply as possible, if the actual code is needed i can paste in.

Class View {
    // Construct Requests User Model
}

Class Controller {
    // Construct Requests User Model & Class View
    $this->user->set($newuserid);
    $this->view->display('file');
}

So Controller is instantiated, since View is set as a dependencies it is instantiated and passed to Controller via __construct . Everything is fine, but for things like a profile page. Where i set a new user ( illustrated above ) setting the new userid also alters the userid that is contained within the View User Model. I am not using static vars so i am confused as to why changed made in controller affect the view user model. This causes an issue for me because the logged in User's ID is set via entry point of site ( bootstrap ) & errors are caused when the profile page overwrites the logged in users id. I have added a newInstance option within my factory, to instead instantiate a new user model for the user profile. Things work fine, but i am still curious as to why i had/have this issue.

In PHP5, variables that hold objects do not contain the actual object itself, but an identifier to reference the actual object.

So when you pass objects around, you actually pass a copy of the identifier to the object which of course points to the same object.

PHP Docs on Objects and references

So when you use the same user object in both, your Controller and your View and manipulate it, the actual User Object will be changed. Since both object variables still hold the same identifier to the object, the objects state will be the same in your Controller as well as in your View.

<?php

class User {

    protected $name;

    public function __construct($name)
    {
        $this->setName($name);
    }

    public function getName()
    {
        return $this->name;
    }

    public function setName($name)
    {
        $this->name = $name;
    }

}

class View {

    protected $user;

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

    public function render()
    {
        echo $this->user->getName();
        $this->user->setName('Tony');
    }

}

class Controller {

    protected $user;
    protected $view;

    public function __construct( User $user, View $view )
    {
        $this->user = $user;
        $this->view = $view;
    }

    public function someAction()
    {
        $this->user->setName('Thomas');
        $this->view->render();
        echo $this->user->getName();
    }

}

$user = new User('Jeffrey');
$view = new View($user);
$controller = new Controller($user, $view);

$controller->someAction(); // Output: ThomasTony

The cruicial thing to understand is that both, the View and the Controller are referencing the same object, thus manipulating the object in one class will result in also manipulating it in the other class (technically that's wrong because both just point to the same object).


Now let's use the clone keyword in the View:

public function __construct( User $user )
{
    $this->user = clone $user;
}

Now the $user property of the view will hold a "pointer" to a copy of the user object. Changes made on that object will not affect the initial object that was passed.

Thus the output will be: JeffreyThomas

I want to lose a few words of caution:

  • Instead of cloning the object you should rather make sure to have clean way of flow of your objects. Your View should not manipulate the state of the User once it got passed.
  • Using clone can lead to undesired behavior. If someone passes an object to one of your classes and expects class to alter the objects state (we're not talking about "Views" here) while it doesn't it can give them a very hard time of debugging.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM