I have a parent class A and a child class B. My goal now is to initialize content (property of A). Only B knows the value that should go inside A::content.
class A
{
protected $m;
protected $n;
protected $p;
protected $content;
public function __construct() {
$this->init();
$b = new B;
$this->content = $b->getContent();
}
private function init() {
$this->m = 'Nobody';
$this->n = 'is';
$this->p = 'like';
}
public function getContent() {
return $this->content;
}
}
class B extends A
{
protected $x;
public function __construct() {
$this->init();
$this->content = $this->m.' '.$this->n.' '.$this->p.' '.$this->x.' (according to '.$this->x.')';
}
private function init() {
$this->x = 'Donald Trump';
}
}
$a = new A;
echo $a->getContent();
In my project I have some classes - let's say B,C,D (they look like B in the code above). They all have one thing in common: They need the variables and methods of A to set the value for A::content.
My question now is: Is this a "good" way to achive the goal? An alternative option could be not to use inheritance but to inject an instance of A into the constructor of B... or maybe other alternatives?
EDIT:
Okay... looks like I was not able to make myself clear. Unfortunately my english is not good enough to make my point clearer.
I'm new to OOP and I'm not trying to realize all S.O.L.I.D. principles. What I'm trying is to understand
1. where am I?
2. where do I want to get?
3. how can OOP helf me to get there?
EDIT:
in my real project I'm instantiating the parent (last two lines of my code). And the parent decides (by parsing $_GET) which child to instantiate : B, C or D
I solved the problem by changing the constructor of B... thanks to #A.P.'s hint
public function __construct() {
parent::init();
$this->init();
$this->content = $this->m.' '.$this->n.' '.$this->p.' '.$this->x.' (according to '.$this->x.')';
}
Bellow are my corrections to make what you are trying to do work. However you cannot create a A class and expect it to get the data from the B class (which is a child)
But you can access the constructor of the A class from the B class
class A
{
protected $m;
protected $n;
protected $p;
protected $content;
public function __construct() {
$this->init();
}
private function init() {
$this->m = 'Nobody';
$this->n = 'is';
$this->p = 'like';
}
public function getContent() {
return $this->content;
}
}
class B extends A
{
protected $x;
public function __construct() {
parent::__construct();
$this->init();
$this->content = $this->m.' '.$this->n.' '.$this->p.' '.$this->x.' (according to '.$this->x.')';
}
private function init() {
$this->x = 'Donald Trump';
}
public function getContent() {
return $this->content;
}
}
$B = new B;
echo $B->getContent();
Related
Have a look at the following example:
class A {
protected $a;
public function __construct() {
$this->a = "foo";
}
}
trait Q {
protected $q;
public function __construct() {
$this->q = "happy";
}
}
class B extends A {
use Q;
protected $b;
public function __construct() {
$this->b = "bar";
}
}
trait X {
protected $x;
public function __construct() {
$this->x = "lorem";
}
}
class C extends B {
use X;
protected $c;
public function __construct() {
$this->c = "sure";
}
public function giveMeEverything() {
echo $this->a." ".$this->b." ".$this->c." ".$this->x." ".$this->q;
}
}
$c = new C();
$c->giveMeEverything();
This works just fine - the output is:
sure
The thing is that I want all classes and and traits within the tree to initialize their member variables. Desired output:
foobarsureloremhappy
It must not be solved with constructors! I just want the member variables to be populated on initialization, but I still had no good idea how to solve this. In a real world example this is more complex, therefore please do not $a = "foo"; just within the variables declaration.
The problem is that traits cannot be instantiated so __construct() is kind of meaningless.
The best approach is to initialize your member variables using the class constructor; that's why constructors exist.
If you want to initialize some members that are declared in a trait, then have a trait function and call it in the appropriate class constructor, example:
trait Q {
protected $a;
public function initQ() { $this->a = "whatever"; }
}
class MyClass {
use Q;
public function __construct() {
$this->initQ();
}
}
I've been running in circle for a couple hours with this problem.
Maybe it's not possible at all, or maybe there's a better OOP solution for this...
For example: I have two classes
class Base
{
public static $config;
}
class System extends Base
{
public function __construct()
{
self::$config = 2;
}
}
class Core extends Base
{
public function __construct()
{
self::$config = 3;
}
}
I always access those classes as singletons: System::HelloWorld(), Core::DoStuff();
I want the $Config attribute to be inherited from the Base class because I'm gonna need it in
almost every single class, so why define it every time over and over again.
The problem is, $Config attribute overrides itself as sonn as another class sets it's own value to it:
System::$config = 2;
Core::$config = 3;
print System::$config // it's 3 instead of 2
I do understand why that happens: Because the Base::$Config is Static - and that way - shared trough all the children. I do not want this, I want it to be static in each child, but not trough of it's children. It would be no problem, if I would actually instantiate the System and the Core classes, but I need them as Singletons...
Help me out here, maybe you know a better design pattern then this.
You don't need to use static variable at all,
<?php
Class Base{
public $Config;
}
Class System Extends Base{
Public static $obj = null;
Public static Function HelloWorld() {
if (!System::$obj) System::$obj = new System();
// call the object functions
// $obj->HelloWorld();
}
Public Function __Construct()
{
$this->Config = 2;
}
}
Class Core Extends Base{
Public Function __Construct()
{
$this->Config = 3;
}
}
?>
I came up with a relatively good solution for this. For those who may face the same problem, see here
<?php
// static change the attributes of the scope
class base
{
public static $config;
}
class a extends base
{
public function __construct()
{
self::$config = 1;
}
}
class b extends base
{
public function __construct()
{
self::$config = 2;
}
}
a::$config = 2;
b::$config = 3;
echo a::config, ',', b::$config; // 3,3
$a = new a();
echo base::$config, a::$config, b::$config, $a::$config; // 1 1 1 1
I want to define a method once in a base class and call it in successive constructors in a class hierarchy. Each time is it called I want it to operate on the properties of the class from which it is called.
For example, A is the base class and the method is defined here. B inherits from A, and C inherits from B.
When I instantiate the concrete class C the constructor will call the base class method, and I want it to operate on the properties of C. (This will be a private array which I will populate when I initialise it).
The constructor of C then calls parent::__construct. When the B constructor calls the base class method, the method should operate on the properties of B. Before the B constructor is complete it will call parent::_construct, and the A constructor will operate on the properties of A.
I was looking into LSB, but it won't work correctly because parent::__construct is a forwarding call. I tried using the result of get_parent_class() in place of parent::, but my calls to static::propertyName error out because propertyName is not a constant.
How can I do this?
EDIT: Here's a code example. The code below outputs "P Q P Q P Q". I want it to output "P Q R S T U".
class A {
private $property = array('P','Q');
function __construct() {
$this->myMethod();
}
public function myMethod() {
foreach ($this->property as $value) {
echo $value . " ";
}
}
}
class B extends A {
private $property = array('R','S');
function __construct()
{
parent::__construct();
$this->myMethod();
}
}
class C extends B {
private $property = array('T','U');
function __construct()
{
parent::__construct();
$this->myMethod();
}
}
$c = new C();
As far as I know it is not possible. In case of private the variable is not available to method and in case of public/protected its overwritten.
You can get your desired result by passing
$this->property
in each myMethod call like this -
$this->myMethod($this->property)
and changing your myMethod definition accordingly.
If I got you right, this is your example:
class A {
public function __construct() {
}
public function someMethod($arg) {
$someProperty = $arg;
}
}
class B extends A {
public function __construct() {
parent::__construct();
}
}
class C extends B {
private $someProperty;
public function __construct() {
parent::__construct();
}
}
Everything works as you would expect. There is only one problem; class A has no property someProperty. If you want to use it in class A, you have to define it there. If you want to use it in subclasses, you have to make it protected. Your class A has therefore to look like this:
class A {
protected $someProperty;
public function __construct() {
}
public function someMethod($arg) {
$this->someProperty = $arg;
}
}
Now you can use it in class B and C, and class A can use the property with someMethod:
$instance = new C();
$instance->someMethod("test");
Because your example has $property defined as private and you never override myMethod, when an object of type C or B is instantiated, it runs class A's constructor, which calls myMethod() from class A where the value of $property is array('P', 'Q');.
If you want it to print 'P Q R S T U' you'll have to override myMethod() and call it from each individual class' __construct() method, OR declare $property to be protected so that the child classes can overwrite its value.
Something like this:
class A {
private $property = array('P','Q');
function __construct() {
$this->myMethod();
}
public function myMethod() {
foreach ($this->property as $value) {
echo $value . " ";
}
}
}
class B extends A {
private $property = array('R','S');
function __construct()
{
parent::__construct();
$this->myMethod();
}
public function myMethod() {
foreach ($this->property as $value) {
echo $value . " ";
}
}
}
class C extends B {
private $property = array('T','U');
function __construct()
{
parent::__construct();
$this->myMethod();
}
public function myMethod() {
foreach ($this->property as $value) {
echo $value . " ";
}
}
}
$c = new C();
OR THIS:
class A {
protected $property = array('P','Q');
function __construct() {
$this->myMethod();
}
public function myMethod() {
foreach ($this->property as $value) {
echo $value . " ";
}
}
}
class B extends A {
protected $property = array('R','S');
function __construct()
{
parent::__construct();
$this->myMethod();
}
}
class C extends B {
protected $property = array('T','U');
function __construct()
{
parent::__construct();
$this->myMethod();
}
}
$c = new C();
proptery cannot be overloaded in child classes. Once you have a C, it does not have the private properties of A anymore. It has no way to access them (outside of reflection). The only way you would be able to do this would be to pass the properties to someMethod in a chain, but this requires access to the desired property.
Using protected would not work either because then the children would just override the parent property.
The solution to this is not have have C be an a (is-a) but have C have the properties of an A (has-a .. composition). This would require some rework of your hierarchy, though, and your calls would have to be more explicit. Something like
class C {
private $b;
private $properties = array('T', 'U');
public function __construct(B $b) {
$this->b = $b;
}
public function someMethod() {
$this->b->someMethod($properties);
}
}
class B {
private $properties = array('R', 'S');
private $a;
public function __construct(A $a) {
$this->a = $a;
}
public function someMethod($properties) {
$this->a->someMethod(array_merge($this->properties, $properties));
}
}
class A {
private $properties = array('P', 'Q');
public function someMethod($properties) {
//your implementation plus an array_merge
}
}
This obviously increases verbosity in your definitions, which is bad. You may want to reconsider why you have to do some things the way you are doing them. You may be able to get around this with traits (assuming you have PHP 5.4)
From php manual:
[...] Static method calls are resolved at compile time.
When using an explicit class name the method is already identified completely and no
inheritance rules apply. If the call is done by self then self is translated to
the current class, that is the class the code belongs to.
Here also no inheritance rules apply [...]
..so im looking for a way to emulate the standard oop inheritance with static singleton.
Code explain better:
// Normal inheritance: my goal.
class Foo{
public function test(){
echo "Foo->test()\n";
}
}
class Bar extends Foo{
public function other_test()
{
echo "Bar->other_test()\n";
}
}
$obj = new Bar();
echo get_class($obj) . "\n";
$obj->test();
$obj->other_test();
/*
Output:
Bar
Foo->test()
Bar->other_test()
*/
// How i would love to do:
class Foo2{
public static function test2()
{
echo "Foo2::test2()\n";
}
// Singleton?
public static $_instance;
public static function get_instance()
{
if(is_null(self::$_instance))
{
self::$_instance = new self();
}
return self::$_instance;
}
}
class Bar2 extends Foo2{
public static function other_test2()
{
echo "Bar2::other_test2()\n";
}
}
$obj2 = Bar2::get_instance();
echo get_class($obj2) . "\n";
$obj2::test2();
$obj2::other_test2();
/*
Output:
Foo2
Foo2::test2()
Fatal error: Call to undefined method Foo2::other_test2()
*/
echo "\n-------\n";
// How im doing actually:
interface Foo3{
public static function get_instance();
}
class Bar3 implements Foo3{
// Singleton?
public static $_instance;
public static function get_instance()
{
if(is_null(self::$_instance))
{
self::$_instance = new self();
}
return self::$_instance;
}
public static function test3()
{
echo "Bar3::test3()\n";
}
public static function other_test3()
{
echo "Bar3::other_test3()\n";
}
}
$obj3 = Bar3::get_instance();
echo get_class($obj3) . "\n";
$obj3::test3();
$obj3::other_test3();
/*
Output:
Bar3
Foo3::test3()
Bar3::other_test3()
*/
The last 'way' force me to avoid the get_instance and static variables to be placed in the parent class, so I do not consider it as a best solution.. if for some reason my get_instance() function will change in the future, i dont want to edit all classes (inheritance! inheritance! we all want inheritance!)
So, is there a way or a best practices to solve this problem?
p.s: php5.3.2
The Singleton pattern in PHP is something like this:
class Singleton {
private static $instance = null;
// Constructor is private, so class cannot be instantiazed from outside
private function __construct() {
}
public static function getInstance() {
if (static::$instance === null) {
static::$instance = new Singleton();
}
return static::$instance;
}
public static function test() {
echo 'Singleton::test()';
}
public function __sleep() {
throw new Exception('Serialization is not alowed.');
}
public function __wakeup() {
throw new Exception('Serialization is not alowed.');
}
public function __clone() {
throw new Exception('Cloning is not alowed.');
}
}
For you is important that keyword static, then this:
class B extends Singleton {
public static function test2() {
echo 'B::test2()';
}
}
$b = B::getInstance();
B::test();
B::test2();
// Singleton::test()
// B::test()
Is this you looking for?
I'd like to start by showing a test case:
class A {
public static $instance=null;
public function __construct(){
self::$instance=$this;
}
public function className(){
return get_class(self::$instance);
}
}
class B extends A {
public function className(){
return get_class(self::$instance);
}
}
// test code
$b=new B();
echo $b->className; // B
$a=new A();
echo $a->className; // A
echo $b->className; // A <- error: not B any more!
Notes
I'm using a factory+singleton patterns above. Well, somewhat.
I don't need any specs on "implementing patterns correctly". I need problem solving, not KISS violations ;).
Critics might say A should be an interface. Ideally, that's what it should have been, but it's just a simple class, sorry.
The issues lies in the fact that self::$instance is the same for all instances. How do I separate self::$instance for each class?
Edit: I've had this idea:
$GLOBALS['store']=array();
class A {
public static $instance=null;
public function __construct(){
$GLOBALS['store'][__CLASS__]=$this;
}
}
You could store an instance per class name:
class A {
public static function getInstance(){
// Maybe use this function to implement the singleton pattern ...
return self::$instance[get_called_class()];
}
public function className(){
return get_class(self::getInstance());
}
}
You can not do this the clean way.
That is one of the mayor drawbacks on stati propertys: you cannot overrride them.
But you wantet an sollution so.....here is the worarround:
use __calllStatic
<?php
class A {
public static function __callstatic($name,$args)
{
if($name="getClass"){
return 'A';
}
}
}
class B extends A{
public static function __callstatic($name,$args)
{
if($name="getClass"){
return 'B';
}
}
}
echo A::getClass();
echo B::getClass();
?>
the output of this is "AB";
You can add a public static $instance=null; declaration in class B.
class A {
public static $instance=null;
public function __construct(){
self::$instance=$this;
}
public function className(){
return get_class(self::$instance);
}
}
class B extends A {
public static $instance=null;
public function className(){
return get_class(self::$instance);
}
}
// test code
$b=new B();
echo $b->className(); // B
$a=new A();
echo $a->className(); // A
echo $b->className(); // Now returns B, as desired.