So, I tried to Google this but don't know what this kind of situation is called...
I'm working on my first use of class inheritance, where a parent class defines a set of methods and then several other classes extend that parent.
What I was wondering, is it possible to do something like this:
class foo {
private bar = false;
private baz = NULL;
}
Now let's say I have:
class foobar extends foo { }
I'd like to be able to have a condition in "foo" that says if any class extends "foo" and sets "bar = true" then "baz" must be set (ie. not null), or else throw an exception.
Is such a thing possible?
This seems possible by using a magic setter function that you define in foo, but comes with a serious caveat. Magic getters and setters fire only when you access an inaccessible property.
When operating inside a class, all properties, no matter whether declared private, public or protected, are usually accessible, so the magic getter and setter functions will not fire. There is only one exception: Properties that were declared private in an ancestor class. Those will be hidden (inaccessible) to descendant classes, and the magic functions will fire.
This means that you will need to declare bar and baz in foo. It wouldn't work if you would declare them in foobar, because they would become accessible.
With this in mind, the following will work as you want:
class foo {
private $bar = false;
private $baz = NULL;
public function __set($name, $value)
{
if ($name == "bar")
{ if ($value == true)
{
if ($this->baz == null)
throw new Exception();
}
}
}
}
class foobar extends foo {
function test()
{
$this->bar = "TEST";
}
}
$foobar = new foobar();
$foobar->test(); // Will throw an exception
If you want to read bar and baz from within foobar, you will also need to define a magic getter function.
Just run a construct function in the second class.
class foo {
private bar = false;
private baz = NULL;
public function __construct() {
if ($this->bar && is_null($this->baz)) // throw exception
}
}
class foobar extends foo {
public function __construct($baz) {
$this->baz = $baz;
$this->bar = true;
parent::__construct(); // Now run the parent's constructor
}
}
Many different ways to do it...
Related
Declare a private property on a Parent class, and then redeclare that property as public or protected on a Child class.
When you create an instance of the Child class, and invoke a method that is inherited from the Parent class. The property on the Parent class is used, and not the property on the Child class.
This is not the case if the initial declaration of the property on the Parent class is public or protected.
Could someone explain to me why this is?
<?php
class P {
private $foo = 'bar';
public function e()
{
echo get_class($this);
echo "\n";
echo $this->foo;
echo "\n";
}
}
class C extends P
{
protected $foo = 'baz';
}
$parent = new P();
$child = new C();
$parent->e();
$child->e();
Output:
P
bar
C
bar
Expected Output:
P
bar
C
baz
Private properties are, as the name implies, private. This means they only be accessed from within the class. As others have mentioned in the comments, this question offers a very good in depth explanation of variable scope in PHP, so by all means go check it out, it's an interesting read.
In your specific however, you seem to be concerned about renaming/overloading variables in a child class. More specifically, we're looking at what happens when a parent and child class happen to both have a property of the same name, and the parent class has a function which return that property.
class A {
private $foo = 'bar';
public function getFoo() {
return $this->foo;
}
}
class B extends A {
protected $foo = 'something something';
}
$b = new B;
echo $b->getFoo();
In the example above, the output would be bar, and that's actually the expected behavior. Since the function getFoo is not overwritten in the child class, PHP executes the function in the parent class. When it gets there, $this refers to A and therefore prints the value of $foo as it is defined in A. It's interesting to note that in this specific example, the scope of B::foo does not matter. In fact, it could omitted entirely and the code would still run perfectly fine.
We can experiment with different function scopes and see what happens:
class A {
private $foo = 'bar';
public function getFoo() {
return $this->foo;
}
private function getCapitalizedFoo() {
return strtoupper($this->foo);
}
protected function getDoubleFoo() {
return $this->foo . $this->foo;
}
}
class B extends A {
protected $foo = 'something something';
public function getParentDoubleFoo() {
return parent::getDoubleFoo();
}
}
$b = new B;
echo $b->getFoo().PHP_EOL; // Output: bar
echo $b->getParentDoubleFoo(); // Output: barbar
echo $b->getDoubleFoo(); // Output: Uncaught Error: Call to protected method ...
echo $b->getCapitalizedFoo(); // Output: Uncaught Error: Call to private method ...
Now, the question remains: How can you access private members from a parent class?
If you have read on the subject, you probably know that, unless completely necessary, your object's properties should be private so as to encapsulate its logic and data as much as possible. Knowing that, the best to allow a child class to access and modify its parent's class properties is by creating accessors and mutators for them.
class A {
private $foo = 'foo';
private $bar = 'bar';
public function setFoo($foo) {
$this->foo = $foo;
}
public function getFoo() {
return $this->foo;
}
protected function setBar($bar) {
$this->bar = $bar;
}
protected function getBar() {
return $this->bar;
}
}
class B extends A {
public function __construct() {
parent::setFoo('more foo');
parent::setBar('more bar');
}
public function getCapitalizedFoo() {
return strtoupper(parent::getFoo());
}
public function getCapitalizedBar() {
return strtoupper(parent::getBar());
}
}
$b = new B;
echo $b->getCapitalizedFoo(); // Output: MORE FOO
echo strtoupper($b->getFoo()); // Output: MORE FOO
echo $b->getCapitalizedBar(); // Output: MORE BAR
echo strtoupper($b->getBar()); // Output: Uncaught Error: Call to protected method ...
By creating public functions to access and modify the parent class' properties you allow the child class to overwrite them and perform logic of its own without having to duplicate the variable. However this also means that any instance of B can potentially alter the values defined in A. In order to mitigate this, you can create protected function that will allow B to internally access and consume the parent class attributes, but the code that consumes B will not be able to do the same.
Let's say I have a huge class named Foo.
if I have to call this class several times in different classes, what is the best way to use it?
Note: Bar is not the only class that will use Foo.
Option #1 (create object when its needed):
class Bar
{
public function myMethod($arg)
{
$foo = new Foo();
$something = $foo->doSomething($arg);
return $something;
}
}
Option #2 (create it once):
class Bar
{
protected $foo;
public function __construct()
{
$this->foo = new Foo();
}
}
Option #3 (make Foo static):
class Bar
{
public function myMethod($arg)
{
return Foo::doSomething($arg);
}
}
Option #4:
// tell me the proper way to do it
The best way I'd say is to instantiate Foo outside the Bar class and inject it as a dependency - the best way to do this would be via constructor:
class Bar
{
private $foo;
public function __construct(Foo $foo)
{
$this->foo = foo;
}
}
$foo = new Foo();
$bar = new Bar($foo);
Then do the same for all classes that have Foo as a dependency. You can reuse the instance if it is suitable or you can create a new one if needed.
I have been searching for this since a couple of days but found no solution.
Here's my code:
// Main class
class My_Parent {
private $foo = '';
// The constructor is set. Now all extended classes will get it.
function __construct() {
var_dump( $foo );
}
function set_val( $value ) {
$this->foo = $value;
}
}
// Extended class
class My_Child extends My_Parent {
// Here's the problem. I've modified the constructor
function __construct() {
parent::set_val( 'bar' );
parent::__construct(); // I don't want to call the parent costructor again
}
}
new My_Child();
This just work fine but not as I expect. I don't want to modify the constructor so I need to call it again from the parent. Which looks weird. I'm going to make an extendable framework for my projects. So, this thing is annoying.
I do want something like this:
class My_Child extends My_Parent {
// Just set the value somehow. do not modify the constructor
$this::set_val( 'bar' );
}
new My_Child();
So that, I don't have to call the constructor again. But the code above throws a syntax error.
Any hope about this?
Just found a tricky solution.
First I've set up an empty function and called it in the constructor of parent class. Then I modified the variable through that function in extended class. The code looks like this:
// Main class
class My_Parent {
private $foo = '';
// The constructor is set. Now all extended classes will get it.
function __construct() {
// We open the portal so that the value can change
$this->portal();
// Then we use the value as we want
var_dump( $foo );
}
function set_val( $value ) {
$this->foo = $value;
}
// This function will play the role of constructor of extended classes
function portal() {
}
}
// Extended class
class My_Child extends My_Parent {
// We just use portal to set the value. Constructor is still untouched!
function portal() {
parent::set_val( 'bar' );
}
}
new My_Child();
This is working perfectly as I wanted. Everything is explained in comments.
Maybe you're over-thinking this. If you want to initialize the property with a constant value, you can simply declare it protected and override it in the subclass:
class MyParent {
protected $foo = 'bar';
// ...
public function getFoo() {
return $this->foo;
}
}
class MyChild extends MyParent {
protected $foo = 'baz';
}
echo (new MyParent())->getFoo(); // "bar"
echo (new MyChild())->getFoo(); // "baz"
Is it bad instantiating objects in the constructor like this below?
class Foo
{
public function fooMethod() {
return 'foo method';
}
}
class Too
{
public function tooMethod() {
return 'too method';
}
}
class Boo
{
public $foo;
public $too;
public function __construct()
{
$this->foo = new Foo();
$this->too = new Too();
}
}
If so, how bad can it be? How should it be done properly?
Manually instantiating classes inside another class creates implicit dependencies, which are quite hard to maintain - you will have a hard time detecting what needs to be changed if you ever need to change those Foo and Too classes.
So, a better way of managing dependencies is:
class Foo
{
private $_bar;
function __construct(Bar $bar)
{
$this->_bar = $bar;
}
}
This way, your object dependency is explicit. Another advantage of doing this, is that some PHP frameworks, (Laravel, Zend, Symfony), allow for an automatic dependency resolution. It means, that you don't instantiate your object manually, only via some sort of factory - like this (Laravel):
$foo = App::make('Foo');
And an App factory automatically detects your Foo class dependencies with some reflection magic and injects them appropriately. Other frameworks have similar capabilities, too.
Also, there are some general principles in OOP, called SOLID which help to develop better OOP design. One of them - D, stands for Dependency Inversion. What it means, is that you should avoid hard dependencies, like in your code. Instead, both Foo and Bar classes should depend on an interface, like this:
interface BarInterface
{
function doBar();
}
class Bar implements BarInterface
{
function doBar()
{
print "Doing BAR";
}
}
class Foo
{
/**
* #var BarInterface
*/
private $bar;
function __construct(BarInterface $bar)
{
$this->bar = $bar;
}
}
Now, if you ever need to change that Bar class with something else, all hell won't break loose, if your replacement also implements that BarInterface.
It's not inherently bad.
The downside is that it decreases the "testability" of your class, simply because Boo is now dependent on the existence Foo and Too.
This depends on the size of your project.
On large projects, or long term projects, it should be changed slightly.
Ideally, you would refactor it implement Dependency Injection pattern, and maybe use a Factory to instantiate it.
Some sample code:
interface FooInterface { function fooMethod(); }
class Foo implements FooInterface { function fooMethod(){return 'Foo';} }
interface TooInterface { function tooMethod(); }
class Too implements FooInterface { function tooMethod(){return 'Too';} }
class Boo
{
public $foo;
public $too;
public function __construct(FooInterface $foo, TooInterface $boo)
{
$this->foo = $foo;
$this->too = $boo;
}
}
class BooFactory
{
public static function create()
{
return new Boo(new Foo, new Too);
}
}
It depends of your requirement and the classes.
Let's says that every call to the constructor of Foo/Too you will execute a huge query to the database to get data, in that scenario I would opt to use lazy instantiation.
Of course, it's a good practice to initialize your properties on the constructor, but on real life performance could your enemy.
Example:
class Boo {
private $foo = null;
private $too = null;
public function __construct() {
//Do something else
}
public function getFoo() {
if (is_null($this->foo)) {
$this->foo = new Foo();
}
return $this->foo;
}
public function getToo() {
if (is_null($this->too)) {
$this->too = new Too();
}
return $this->too;
}
public function aMethodThatUsesFoo() {
$foo = $this->getFoo();
$foo->fooMethod();
}
public function aMethodThatDoesntUsesFoo() {
echo "Hello!, I don't need foo or too to execute this method";
}
}
if you use this class only to execute aMethodThatDoesntUsesFoo(), it will never call the constructors of Foo/Too.
$boo = new Boo();
$boo->aMethodThatDoesntUsesFoo();
if you will only execute aMethodThatUsesFoo(), it will only instantiate Foo
$boo = new Boo();
$boo->aMethodThatUsesFoo();
You can do this by static methods as well.
Here's some working code:
class A {
public $Foo;
public function GetFoo() {
$this->Foo = 'Bar';
}
}
class B extends A {
function __construct() {
$this->GetFoo();
echo $this->Foo;
}
}
$b = new B(); // Outputs "Bar"
Is there any way I can make this "prettier" (i.e. without the A::GetFoo() method)? I would've thought that wrapping the population of the $this->Foo inside a A::__construct() would work, but it doesn't.
Just to wrap it up, here's what I want: class A instantiates my DB object and that object is usable for every child class of A.
Perhaps you're overriding the parent's constructor without calling in from B?
class A {
protected $Foo = null;
public function __construct() {
$this->Foo = 'Bar';
}
}
class B extends A {
public function __construct() {
parent::__construct();
echo $this->Foo;
}
}
From the PHP manual:
"Class properties must be defined as
public, private, or protected. If
declared using var without an explicit
visibility keyword, the property will
be defined as public."
So, your class B can see $this->Foo. You don't have to call GetFoo() first. You must, however, call the parent constructor first if you need to reference $this->Foo inside of your constructor for class B.