Ok, so, with the code below:
class Core {
public $child;
public function start() {
$child = Loader::instance('Child');
print_r($this);
}
}
class Loader extends Core {
public static $instances;
public static function instance($class) {
if(!isset(self::$instances[$class])) {
self::$instances[$class] = new $class();
}
return self::$instances[$class];
}
}
class Child extends Core {
public function __construct() {
parent::__construct();
$this->child = 'test';
}
}
Loader::instance('Core')->start();
I should be able after a print_r($this) to see:
Core Object
(
[child] => test
)
instead of
Core Object
(
[child] =>
)
what is happening now?
Thanks again..
Within the start() method of Core class you use variable $child, that is not the property of the object. Instead write:
class Core {
public $child;
public function start() {
$this->child = Loader::instance('Child')->child;
print_r($this);
}
}
and tell me, whether this is what you wanted to accomplish.
EDIT:
I believe you can achieve what you want by referencing static variables. But be careful, how they work. Moreover, you will not see the result by invoking print_r().
Here is the code:
class Core {
static $child;
public function start() {
// invoking code that changes Core::$child inside
$child = Loader::instance('Child');
print_r($this);
}
}
and
class Child extends Core {
public function __construct() {
parent::__construct();
// changing static variable $child of both Core and Child
self::$child = 'test';
}
}
$child = Loader::instance('Child');
Shoulld be:
$this->child = Loader::instance('Child');
This is where your print_r output comes from:
$child = Loader::instance('Child');
print_r($this);
And it will print the current object ($this is a Core), rather than the newly instantiated $child (which would be a Child class).
Related
I have a core class as a collector and two subclasses stored in public variables in this core class:
class Core
{
public $cache;
public $html;
public function __construct()
{
$cache = new Cache();
$html = new Html();
}
}
class Cache
{
public function __construct()
{
}
public function store($value)
{
// do something
}
}
class Html
{
public $foo;
public function __construct()
{
$foo = "bar";
global $core;
$core->cache->store($foo);
}
}
QUESTION:
I would like to get rid of the line "global $core" and do something like:
$this->parent->cache->store($foo)
$cache should be connected to $core in some way because it is a public member of $core
I know that $html is a subclass stored as a variable and not an inheritance.
Any ideas?
Second question: Can I leave out the empty constructor in the Cache-Class?
What you can do is to use the concept of dependency injection to inject in your HTML class an object of the class Cache, and then, use it to call method store. I believe that this is a very good approach. So you can do something like this.
class Core
{
public $cache;
public $html;
public function __construct()
{
$cache = new Cache();
$html = new Html($cache);
}
}
In your class HTML:
class Html
{
public $foo;
public function __construct(Cache $cache)
{
$foo = "bar";
$cache->store($foo);
}
}
About your second question, if there is no necessity of do something in the constructor, you could just ommit it. But there is no problem to let it empty as well. So I think that it up to you.
Your object can't access caller class methods, because he do not know anything about it's caller.
You can try to pass parent when creating new object
class Core {
public $cache;
public $html;
public function __construct() {
$this->cache = new Cache($this);
$this->html = new Html($this);
}
}
class Html {
public $parent;
public function __construct($parent) {
$this->parent = $parent;
if (!empty($this->parent->cache)) {
$this->parent->cache->store();
}
}
}
Can I leave out the empty constructor - yes, you even do not have to declare __construct method at all, as all classes has it's default constructor/destructor.
I have a parent class that depends on whether child class are instantiated.
class GoogleApp {
protected $auth_token;
public function __construct($scopes) {
$this->auth_token = $scopes;
}
}
class Gmail extends GoogleApp {
public function __construct() {
print_r($this->auth_token);
}
}
$googleApp = new GoogleApp('gmail'); // Change the actual class for all child instances
$gmail = new Gmail();
The idea is that all the children use the same auth_token (which is generated on whether the child classes are used - as of now, I'm just manually adding them to whether I included them in my code). Since I have quite a few child classes (like Calendar or Drive), do I have to inject the parent into each child instance or is there an easier way?
If I understand your request correctly, you're pretty close, you just need to declare your property as static.
class FooParent
{
protected static $scope = null;
public function __construct($scope)
{
self::$scope = $scope;
}
public function getScope()
{
return self::$scope;
}
}
class FooChild extends FooParent
{
public function __construct()
{
if (self::$scope === null) {
throw new Exception('Must set scope first.');
}
}
}
$parent = new FooParent('foo');
$child = new FooChild();
echo $child->getScope(), "\n"; // prints "foo"
I try to call getTest() function inside Child class.
First I initialize instance of Ext class so I assume main property $ext should now contain it. But Child class does not inherit it and obtained error message is:
Call to a member function getTest() on a non-object
Where is the issue?
<?php
$A = new Main;
class Main
{
protected $ext = null;
function __construct()
{
$this->ext= new Ext();
new Child;
}
}
class Child extends Main
{
function __construct()
{
echo $this->ext->getTest();
}
}
class Ext extends Main
{
public function getTest()
{
return "cool";
}
}
?>
I know that to solve it other way I can use:
class Child
{
private $Main;
function __construct( &$Main ) { ... }
}
but I would like to understand why that does not work..
At the moment on construct the object the atribute don't have a value yet.
You need call to the parent constructor before use the attribute
function __construct()
{
parent::__construct();
echo $this->ext->getTest();
}
Basically this is what i want to do:
<?php
class App {
public $var = "main-class";
public function load() {
$this->var = "child-class";
$child = new Child;
$child->echo_var();
}
}
class Child extends App {
public function echo_var() {
echo $this->var;
}
}
$app = new Child;
$app->load();
?>
It outputs "main-class", i want it to output "child-class" without having to modify the child class (because i want it to be sort of a "clean" and dynamic class).
I accept suggestions for another course of action
PS: This is part of an Small MVC Framework i'm trying to develop.
There are two ways that you could do this. Both are going to need to use constructors. With the first one, the child will declare itself when created
<?php
class App {
public $var = "main-class";
public function __construct($var=null) {
if($var !== null) {
$this->var = $var;
}
}
public function load() {
$child = new Child ();
$child->echo_var();
}
}
class Child extends App {
public function __construct(){
parent::__construct("child-class");
}
public function echo_var() {
echo $this->var;
}
}
$app = new Child();
$app->load();
?>
The second one allows the parent to declare the name of the child.
<?php
class App {
public $var = "main-class";
public function __construct($var=null) {
if($var !== null) {
$this->var = $var;
}
}
public function load() {
$child = new Child ("child-class");
$child->echo_var();
}
}
class Child extends App {
public function echo_var() {
echo $this->var;
}
}
$app = new Child();
$app->load();
?>
Both of those examples work and do what you want, I believe.
This isn't how inheritance works - By creating a new Child object, its data members are all initialized with their default values. When you do $this->var = "" in the parent class, you're setting the data members for the $app object, not the $child object.
You can modify the child class to incorporate a constructor that accepts parameters, and that constructor would set its data members properly. To achieve something similar to what you want, you can use constructors:
<?php
class App {
public $var = "main-class";
public function __construct() {
$this->var = "child-class";
}
public function load() {
$child = new Child;
$child->echo_var();
}
}
class Child extends App {
public function __construct()
{
parent::__construct();
}
public function echo_var() {
echo $this->var;
}
}
$app = new App;
$app->load();
I find it very strange that your parent class instanciates it's child. Generally, you would instanciate the child, and you get all the functionality of the parent.
$app = new Child();
$app->load();
The problem is that you actually have 2 different instanciations. You have an object of App and it's holding a separate object of Child.
The other way to do this would be to make $var a static variable and then it would be available independent of the instantiation. I don't generally recommend making properties static though. It's generally considered bad form (for numerous reasons).
is it possible to easily and quickly "assigning properties of one object to another"
class a {
public $number_one;
public $number_two;
public $number_three;
function __contruct() {
//do stuff
}
}
class b {
public $my_var;
function __contruct() {
$instanc_a = new a();
extract( $instance ); // but make these extracted object properties of class b????
// how? :-(
echo $this->number_one;
}
}
You can use get_object_vars to copy the public (only) properties of class a to the current object:
class b {
public $my_var;
function __construct() {
$instanc_a = new a();
$vars = get_object_vars($instanc_a);
foreach($vars as $name => $value) {
$this->$name = $value;
}
echo $this->number_one;
}
}
See it in action.
Note: You have a typo in your code (two cases of "contruct" instead of "construct") which will prevent things from working as they should.
Sounds like you actually want class b to extend class a
class b extends a {
public $my_var;
function __construct () {
parent::__construct();
// Now $this refers to anything in class b, or if it doesn't exist here, looks to class a for it
echo $this->number_one;
}
}