【问题标题】:PHP how to reference neighbor class with $this->classname?PHP 如何使用 $this->classname 引用邻居类?
【发布时间】:2019-11-24 08:00:43
【问题描述】:

显然我错过了一些东西。我有以下代码:

<?php

class module {
    protected $registry;
    public $controller;
    public $model;
    public $view;
    public $var = 'global';

}

class controller extends module {
    public function test_controller() {
        echo 'controller test';
        echo $this->var;
        $this->model->test_model();
        $this->view->test_view();
    }
}

class model extends module {
    public function test_model() {
        echo 'model test';
        echo $this->var;
    }
}

class view extends module {
    public function test_view() {
        echo 'view test';
        echo $this->var;
    }
}

$module = new module();
$module->controller = new controller();
$module->model = new model();
$module->view = new view();

echo "\n\n\n" . print_r($module);

$module->controller->test_controller();

最后我得到“在 null 上调用成员函数 test_model()”。我确实理解每次实例化“扩展器”类时都会重新初始化“模块”类的变量。好的,没问题,但在那之后我为“父”类属性分配了所需的“值”(我的意思是 $module->controller = new controller();)。

我不明白如何处理这种行为。我想在我在控制器函数中编写的模块中实现这种类型的引用:$this->model->some_func(), $this->view->some_other()。还将有一个所谓的注册表,其中包含其他类也应该可用于扩展类。

如果这是一个设计问题 - 好吧,请指出我 :)

谢谢。

【问题讨论】:

  • 为什么要扩展模块类?
  • 控制器的实例有一个空模型和视图。
  • 如果你真的想在继承类的不同实例之间共享变量,你可以使用静态属性,你需要以不同的方式引用它们。但这很可能是一种反模式。
  • 我扩展了模块类,因为 $registry 中的功能应该对控制器、模型、视图类可用。这是一回事。另一个是我想从控制器(和其他类)中引用模型和其他类,例如 $this->model、$this->api、$this->controller 等。

标签: php reference extends


【解决方案1】:

这些是不同的实例。下同:

<?php

class Foo
{
    public $bar;
    public $baz;
}

class Baz extends Foo
{
    public function showMeTheBar()
    {
        return $this->bar;
    }
}

$foo      = new Foo;
$foo->bar = 'Hat';
$foo->baz = new Baz;
var_dump($foo->baz->showMeTheBar());

输出:

NULL

$foo 的栏和$foo::baz 的栏不是一回事。

【讨论】:

    【解决方案2】:

    正如其他答案所述,控制器拥有$this-&gt;model$this-&gt;view 的所有权,因此在您的实例中,您必须为控制器分配新实例:

    $module = new module();
    $module->controller         =   new controller();
    # Need to assign to the controller now, not the $module
    $module->controller->model  =   new model();
    $module->controller->view   =   new view();
    

    这可能是你不打算做的。如果你想做你正在做的事情,你必须在$module范围内做,并将单个元素带回module

    <?php
    class module
    {
        public $controller,
               $model,
               $view;
    
        public $var = 'global';
    
        protected $registry;
        # Add a new method that basically does what your controller method was doing.
        # Difference is that now these other classes are in the $module scope
        public function get()
        {
            $this->controller->test_controller();
            $this->model->test_model();
            $this->view->test_view();
        }
    }
    
    class controller extends module
    {
        public function test_controller()
        {
            echo $this->var;
        }
    }
    
    class model extends module {
        public function test_model()
        {
            echo $this->var;
        }
    }
    
    class view extends module {
        public function test_view()
        {
            echo $this->var;
        }
    }
    
    $module = new module();
    $module->model = new model();
    $module->view = new view();
    $module->controller = new controller();
    $model->get();
    

    虽然我不确定您打算分配多少类,但您可能想使用注入:

    $module = new module(new model(), new view(), new controller());
    $module->view->test_view();
    

    如果您注入并想要使用动态注入,您可能需要查看反射,这样您的类就不需要显式参数分配。

    你可以进入动态调用的范围,但如果你不小心,那可能会进入一个兔子洞!

    <?php
    class module
    {
        public $var = 'global';
        protected $registry;
        # Might want to add a getter
        public function __get($prop)
        {
            if(property_exists($this, $prop)) {
                return $this->{$prop};
            }
        }
        # Create a method getter
        public function __call($class, $args = false)
        {
            $class = strtolower(str_replace('get','', $class));
            # Set the dynamic variable
            if(!isset($this->{$class}))
                $this->{$class} = (is_array($args))? new $class(...$args) : new $class($args);
            # Send back new variable
            return $this->{$class};
        }
    }
    
    class controller extends module
    {
        public function test_controller()
        {
             echo $this->var;
        }
    }
    
    class model extends module
    {
        public function test_model()
        {
            echo $this->var;
        }
    }
    
    class view extends module
    {
        public  function __construct()
        {
            print_r(func_get_args());
        }
    
        public function test_view()
        {
            echo $this->var;
        }
    }
    
    # Create instance of module
    $module =   new module();
    # use getView() to fetch and assign view
    print_r($module->getView('arg1', 'arg2')->test_view());
    # Since you set this value already, it can be pulled directly or by using
    # getView()
    print_r($module->view);
    

    你从中得到什么:

    Array
    (
        [0] => arg1
        [1] => arg2
    )
    
    global
    
    view Object
    (
        [var] => global
        [registry:protected] => 
    )
    

    动态调用有它的位置,所以如果你使用它,只要用心去做。

    对于持久变量,如前所述,您可以使用静态变量,因此如果您在一个类中更改变量,它会全部更改。

    【讨论】:

    • 是的,完全正确:我必须手动将这些实例分配给每个需要的类。这样我可以更好地控制谁看到谁。至于“getter”(__get)——我也不得不重新考虑这一点,因为 getter 已经定义为适合 $registry。无论如何,谢谢。
    【解决方案3】:

    Controller::test_controller() 调用为树之前$module 的状态(我将以驼峰式的方式显示类名):

    $module: Module
    Props:
      $controller: Controller
      Props:
        $controller: null
        $model: null
        $view: null
        $var: "global"
      $model: Model
      Props:
        $controller: null
        $model: null
        $view: null
        $var: "global"
      $view: View
      Props:
        $controller: null
        $model: null
        $view: null
        $var: "global"
      $var: "global"
    

    你能看到吗? $module-&gt;controller$module-&gt;controller-&gt;controller 不同。即使$module-&gt;var$module-&gt;controller-&gt;var 也不是一回事。 $module$module-&gt;controller 是不同的。

    我不知道你是否做对了,但解决方案是使用依赖注入;这意味着您应该将(注入)$module(依赖)作为参数传递给Controller::test_controller() 或其他任何参数。

    【讨论】:

    • 是的,我已经意识到了。感谢您的回答。我不得不重新考虑这些关于类的“可见性”的东西,例如视图必须可用于控制器,但控制器不能用于查看等。我重新设计了这个结构。
    【解决方案4】:

    感谢您的回答。事情就是这样发生的:您必须自己提出要求才能找到答案:)

    应用程序的入口点是控制器和 api,所以我必须在那里提供东西,而不是其他地方:'view' 不能看到 'model'。

    因此,如果有人可能正在寻找这种设计 - 它就是:

    $controller = new Controller($registry);
    $model = new Model($registry);
    $api = new Api($registry);
    $view = new Template($modulename);
    //these classes above are already extended by abstract classes to bring $registry classes with __get()
    
    $settings = new Settings($modulename);
    $language = new Language($code);
    
    $module = new stdClass();
    
    $module->controller = $controller;
    $module->controller->model = $model;
    $module->controller->view = $view;
    $module->controller->api = $api; //this might be questionable, but sometimes it's easier to do so
    $module->controller->settings = $settings;
    $module->controller->language = $language;
    
    $module->api = $api;
    $module->api->model = $model;
    $module->api->view = $view;
    $module->api->controller = $controller; //this might also be questionable, but sometimes it's easier to do so
    $module->api->settings = $settings;
    $module->api->language = $language; 
    
    $model->settings = $settings;
    

    目标是进行调用(在控制器和 api 中),如 $this-&gt;model-&gt;method(), $this-&gt;view-&gt;method() 等,我已经设法实现了。

    【讨论】:

      猜你喜欢
      • 2014-09-09
      • 2020-06-12
      • 2020-03-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-08
      • 1970-01-01
      • 2013-01-29
      相关资源
      最近更新 更多