Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PHP:从另一个对象调用对象方法的最佳方法?_Php_Oop - Fatal编程技术网

PHP:从另一个对象调用对象方法的最佳方法?

PHP:从另一个对象调用对象方法的最佳方法?,php,oop,Php,Oop,我正在寻找从另一个类调用类方法的最佳方法,而不必使用Global来获取类实例,因为我现在知道“Global是邪恶的” 下面是一些代码来进一步解释: class Assets{ public $assets = array(); public function add($asset){ $this->assets[] = $asset; } } 现在我想从这里调用Assets/call方法 $assets = new Assets; class Form{ public fun

我正在寻找从另一个类调用类方法的最佳方法,而不必使用Global来获取类实例,因为我现在知道“Global是邪恶的”

下面是一些代码来进一步解释:

class Assets{
 public $assets = array();
 public function add($asset){
  $this->assets[] = $asset;
 }
}
现在我想从这里调用Assets/call方法

$assets = new Assets;
class Form{
 public function __construct(){
  global $assets;
  $assets->add('Form');
 }
}
在这种情况下使用Global有那么糟糕吗?如果是的话,还有什么方式被认为是最好的

PS:我只需要处理类的一个实例;意味着我不想在第二个类中创建新实例。

您可以试试这个

class Form{
 public function __construct(Assets $assets){
  //$assets = new Assets;
  $assets->add('Form');
 }
}

如果您只想拥有一个资产实例,则需要使用某种形式的依赖项注入

在这种情况下,最明显的是通过构造函数传递它:

class Form{
 public function __construct(Assets $assets){
  $assets->add('Form');
 }
}

使用globals确实是个坏主意。

我不是直接用提供的元素来回答这个问题,我只是展示了一种不使用globals在对象之间共享数据的方法

class A {

    private $v;

    function __construct ($value)
    {
        $this->v = $value;
    }

    function set_v ($value)
    {
        $this->v = $value;
    }

    function print_v ()
    {
        echo $this->v;
    }

}

您可以在另一个对象中保留一个对象的跟踪,并考虑对象的封装。 但是,如果删除了A的实例,则B的实例可能变得不可靠。然后,您应该确保数据在存储它的对象中始终是可靠的(例如,制作一个方法来验证内部数据是否正常)

同样正如特雷什科所注意到的,应该避免明确等待引用的论点。事实上,自PHP5.0以来,该语言引入了一个称为类型暗示的新特性。这样可以防止程序出现不希望出现的内存行为,并且可以在编译级别监视任何错误匹配(更多详细信息,请参阅)

因此

function __construct (&$tha) ...
必须重新定义为

function __construct (A $tha) ..

在本例中。

如果在您的上下文中有意义,您还可以将资产设置为:

类别资产
{
/////////////////////
//你的东西//
/////////////////////
private$assets=array();
公共职能部门增加(资产)
{
$this->assets[]=$asset;
}
/////////////////////
//单件物品//
/////////////////////
静态私有$instance=null;
静态公共函数getInstance()
{
if(self::$instance==null)
self::$instance=新self;
返回self::$instance;
}
//将此类的构造限制在此类定义之外
私有函数_构造(){}
//将此类的克隆限制在此类定义之外
私有函数uu clone(){}
}
在您的其他代码中,您将使用如下单例:

class Form
{
    public function __construct()
    {
        Assets::getInstance()->add('Form');
    }
}
那怎么办

<?php
class Assets
{
    protected static $assets = array();

    protected function add($el)
    {
        self::$assets[] = $el;
    }

    public function getAssets()
    {
        return self::$assets;
    }
}

class Form extends Assets
{
    public function __construct()
    {
        parent::add('Form');
    }
}

class Css extends Assets
{
    public function __construct()
    {
        parent::add('Style');
    }
}

$assets = new Assets;
new Form;
new Css;
var_dump($assets->getAssets()); // Prints: array(2) { [0]=> string(4) "Form" [1]=> string(5) "Style" }

依赖项注入是一种方法。我将使用这个工厂机械化将对象实例传递给另一个对象。如(只是一个样本,没有测试):


当然可以,但我只需要处理这个类的一个实例。谢谢。你可以像这样使用构造函数注入,公共函数构造(Assets$Assets);注射无疑是一种方式。将构造隐藏在另一个构造函数中是一种不好的做法,从长远来看,这只会使您的工作更加困难(例如,您发现一个用例,其中相同的资产实例应该从不同的表单实例中使用)是的,这是一种很好的做法。还有一些其他的方法也被认为是“好的”,但是在acedemic OOP设计中,
global
static
或singleton都被认为是不好的。尽量避免这些问题。@Evert,虽然这比任何其他“答案”都要好得多,但您确实应该避免在构造函数中执行任何计算。这会让测试变成一场噩梦。@Evert你能告诉我其他几种方法吗。谢谢。只是研究依赖注入。这很酷,但单身不被认为是一种不好的做法吗?我认为这总是取决于你想做什么。当考虑到一些相当大的项目(比如开源3D引擎)经常使用单例时,我不会说单例通常是一种不好的做法。由于PHP5.0的发布(2004年左右发布),您不应该通过引用传递对象。它扰乱了refcount并导致泄漏。在任何情况下使用globals都是不好的。即使使用纯过程代码,依赖注入也是“语言提供的标准”解决方案。你只是在OOP方面真的很差。也许有点帮助。@Dewan159我想你是从错误的角度来看待这一点的,当一个人从过程的角度开始深入研究面向对象编程(OOP)和PHP并谈论“实践”时,这是很常见的。你知道为什么
global
是“坏的”吗?试着先集中精力。在直截了当地批评语言之前,先发展你对该方法的了解,这样你在寻求帮助时会得到更好的回应。一旦您稍微熟悉了为什么注入很重要(例如,它在Java世界中广泛使用。)@Dewan159我不是在定性地陈述您的问题:)我只是注意到您提供的代码片段表明设计目标是错误的。除了PHP(Python、许多JVM语言、Ruby都有DI的一些变体)之外,您所发现的一个弱点是在许多语言中几乎被普遍接受的编码实践。它是OOP的主干。您倾向于将此模式视为问题,这可能意味着您在编写代码时有一些错误的目标。你提到写一个框架。。。也许我们可以继续聊天?@Dewan159:如果你不希望人们总是传递资产对象,那么就不要强迫他们使用构造函数。提供一个工厂类,您可以将资产实例传递一次,并让工厂始终构造表单类。这与
global
有什么不同?
class Form
{
    public function __construct()
    {
        Assets::getInstance()->add('Form');
    }
}
<?php
class Assets
{
    protected static $assets = array();

    protected function add($el)
    {
        self::$assets[] = $el;
    }

    public function getAssets()
    {
        return self::$assets;
    }
}

class Form extends Assets
{
    public function __construct()
    {
        parent::add('Form');
    }
}

class Css extends Assets
{
    public function __construct()
    {
        parent::add('Style');
    }
}

$assets = new Assets;
new Form;
new Css;
var_dump($assets->getAssets()); // Prints: array(2) { [0]=> string(4) "Form" [1]=> string(5) "Style" }
class UI{

public $somthing = 'Cool';

public function newComponent($name){
    return new $name($this);
}

}

$ui = new UI;
class Form{
    public $ui;

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

    public function say(){
        print $this->ui->somthing;
    }
}

$form = $ui->newComponent('Form');

$form->say(); // print 'Cool'.