在PHP中的扩展类中使用父级变量

6

我有两个类,一个是主类,另一个是扩展类。我需要在扩展类中使用主类的变量。

<?php
class Main {
  public $vars = array();
}

$main = new Main;

$main->vars['key'] = 'value';

class Extended extends Main { }

$other = new Extended;

var_dump($other->vars);

?>

我可以做到吗?

无效的示例:

<?php
class Extended extends Main {
  function __construct ($main) {
    foreach ($main as $k => $v) {
      $this->$k = $v;
    }
  }
}
?>

我需要一些更加透明高效的解决方案 :)

我不明白。我很乐意回答你的问题,但它不够清楚。你是想构建类似于($obj = new Extended($main))的“扩展”,还是在寻找静态变量? - user19302
5个回答

6
使用简单的构造函数即可轻松实现。
<?php

class One {

    public static $string = "HELLO";

}

class Two extends One {

    function __construct()
    {
        parent::$string = "WORLD";
        $this->string = parent::$string;
    }

}

$class = new Two;
echo $class->string; // WORLD

?>

4

编辑:这个问题可以通过控制反转(IoC)和依赖注入(DI)更好地解决。如果你使用自己的框架或一个没有依赖注入容器的框架,可以尝试League/Container

下面是错误答案的历史记录。


我认为正确的方法如下。

<?php
class Config {
    protected $_vars = array();

    protected static $_instance;

    private function __construct() {}

    public static function getInstance()
    {
        if (!isset(self::$_instance)) {
            self::$_instance = new self();
        }
        return self::$_instance;
    }

    public function &__get($name) {
        return $this->_vars[$name];
    }

    public function __set ($name, $value) {
        $this->_vars[$name] = $value;
    }
}

$config = Config::getInstance();
$config->db = array('localhost', 'root', '');
$config->templates = array(
    'main' => 'main',
    'news' => 'news_list'
);

class DB {
    public $db;

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

    public function connect()
    {
        mysql_connect($this->db[0], $this->db[1], $this->db[2]);
    }
}

$config = Config::getInstance();
$db = new DB($config->db);
$db->connect();

class Templates {
    public $templates;

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

    public function load ($where) {
        return $this->templates[$where];
    }
}

$config = Config::getInstance();
$templates = new Templates($config->templates);
echo $templates->load('main') . "\n";

我希望那个不懂PHP但却给我点踩的人能够解释一下为什么。 - OIS
我不会对你进行负面评价,但你在面向对象设计方面确实有所欠缺。你绝不能扩展 Config 类 - Config 对象应该包含在使用它们的对象中 - 而不是扩展到其他类。对不起,但这很荒谬。 - user19302
我不这样做,但那就是那个人想要的。它开始并不是一个配置类,但最终却成为了这样一个类... - OIS
2
拒绝延续愚蠢行为 :) 我完全不怪责楼主,但我们应该足够明智指出楼主做了一个糟糕的设计选择,如果他基于这个“反模式”构建整个代码结构,那么它将会严重影响他的工作。 :) - user19302
修改了代码以反映这是一个配置类,而不是一开始的某个随机主类。 - OIS

2
我意识到这已经非常古老了,但如果有其他人需要提示的话...

你考虑过使用静态变量吗?

PHP面向对象设计模式是这样的:在父类中静态声明的变量在子类中也保持不变。

例如...

<?php
class A {
    public static $test = 'a';

    public function test() {
        echo 'Test is: '.self::$test;
    }

}
class B extends A {
    public static $test = 'b';
}
$obj = new B;
$obj->test();
?>

运行此代码(在PHP 5.3上-我确定其他版本也是一样的),将会给你以下结果:

测试为:a

根据您在原始帖子中提供的信息,您正在寻找一种方法使得父类变量可以保留-即使在扩展类中也是如此。这解决了这个问题。

要在类作用域之外公开调用变量(即您通常会编写$obj->vars的地方),您需要在父类中创建一个引用self::$variable_name的函数,以便它可以将该变量返回到利用该类或任何扩展它的类的代码。

例如,像这样的东西:

public function get_variable() {
    return self::$variable;
}

你还可以创建一个魔术方法,根据你要求实例的方法或变量,在运行时动态地抛出self::$variable。你可以将代码连接到任何情况下等效于self::$variable。
阅读http://php.net/manual/en/language.oop5.magic.php获取更多关于各种魔术方法的信息,它们允许您执行此类操作。
由于原帖有点晦涩,所以我不确定这是否正是你想要的,但我没有看到其他人提到静态变量,所以我来发表一下意见 - 希望能有所帮助!

有趣。但是如果你在__construct()方法中声明和赋值$test会发生什么呢?我问这个问题是因为你不能做public static $this->test;。 - sqram

1

我认为你需要更清楚地表达你的需求。想象一下,如果你有几个Main和Extended的实例,它们应该都引用相同的数据吗?这样,如果你在其中任何一个实例中更改了数据,它们都会受到影响。

如果是这样的话,那么一种方法是使用静态变量,它与类而不是单个实例相关联。另一种方法是创建一个单独的对象(属于不同类),用于存储你的数据,并在创建Main和Extended类时将其传递给它们。它们可以分别存储对它的引用,例如:

class Main {
   public $data;
   function __construct(Data $data) {
     $this->data = $data;
   }
}
class Extended extends Main {}

$ourData = new Data();
$ourData->vars = array(1,2,3);

$main = new Main($ourData);
$other = new Extended($ourData);

如果不是的话,那么你想要的是数据的副本,而不是对同一数据的引用。在这种情况下,你的第二个例子更接近一些,尽管我不会盲目地复制所有成员。

0

噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢噢

你想要这个:

class Config
{
    private $m_vars = array();

    function __get($name)
    {
        return $this->m_vars[$name];
    }

    function & __set($name, $value) // << the & is important!
    {
        $this->m_vars[$name] = $value;
    }
}

class Db
{
    funciton __construct(Config $config)
    {
        $this->Connect($config->host, $config->user, $config->pass, $config->db);
    }
}

$config = new Config();
$config->host = "localhost";
...
$db = new Db($config);

:)

编辑:

另外,你可以这样做:

class Templator
{
    private $m_config = null;
    function __construct($config)
    {
        $this->m_config = $config;
    }

    function PrintTemplate($name)
    {
        echo file_get_contents($this->m_config->template_path . $name);
    }

}

$config->template_path = "./templates/";
$temp = new Templator($config);
$temp->PrintTemplate("index.html");

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接