Using parent variables in a extended class in PHP

2019-04-07 16:14发布

问题:

I have 2 classes, main and extended. I need to use main vars in extended class.

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

$main = new Main;

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

class Extended extends Main { }

$other = new Extended;

var_dump($other->vars);

?>

Who I can do it?

No valid for example:

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

I need some solution more transparent and efficient :)

回答1:

EDIT: This can be solved much better with Inversion of Control (IoC) and Dependency Injection (DI). If you use your own framework or one without Dependency Injection Container try League/Container

Answer below left as history of foolish answers.


The correct way I figure.

<?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";


回答2:

It would be easily possible with a simple constructor

<?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

?>


回答3:

I realize this is super-old, but in case anyone else needs a clue...

Have you considered using static variables?

The PHP OOP design pattern is such that statically declared variables in a parent class remain the same in the child class, too.

For example...

<?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();
?>

Running this code (on PHP 5.3- I'm sure it's the same for other versions, too) will give you the following result:

Test is: a

From what I could gather in your OP, you are looking for a way for the parent class variables to remain - even in extended classes. This solves that problem.

To call the variables publicly outside of the class scope (i.e. where you'd normally write $obj->vars), you'd need to create a function in the parent class that references self::$variable_name so that it can throw that variable back to the code that utilizes either that class, or any other class that extends it.

For example, something like:

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

You could also create a magic method that would dynamically throw back the self::$variable based on what you ask the instance for - i.e. a method or a variable. You could wire the code to throw back the self::$variable equivalent in any case.

Read http://php.net/manual/en/language.oop5.magic.php for more info on the various magic methods that allow you to do this kind of stuff.

The OP was a bit cryptic so I wasn't sure if that's exactly what you wanted, but I didn't see anyone else here reference static variables so thought I'd chime in - hope it helps!



回答4:

I think you need to be more clear about what you want. Imagine that you had several instances of both Main and Extended. Should they all refer to the same data, so that if you change the data in any one of them, they're all affected?

If so, then one approach is to use a static variable, which is tied to the class rather than the individual instance. Another is to create a separate object (of a different class) to store your data, and pass it to the Main and Extended classes when they're created. They could each store a reference to it, e.g.:

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);

If not, then you want copies of the data, rather than references to the same data. In that case, your second example is closer, although I wouldn't just blindly copy all members.



回答5:

oooooooooooooooooooooooooooooooooooooooooooooooooooooh

you want this:

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);

:)

EDIT:

also, you can do this:

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");