Accessing a property from an extended class - php

<?php
class BaseController extends Controller
{
protected $foo;
public function __construct()
{
$this->foo = '123';
}
protected function setupLayout()
{
if ( ! is_null($this->layout))
{
$this->layout = View::make($this->layout);
}
}
}
Above is the BaseController and I want to declare foo as 123, but can I get the foo variable in the controller which I have extended from this basecontroller, can you help?
public function detail($action)
{
return $this->foo;
}

As per docs:
http://php.net/manual/en/language.oop5.decon.php
Note: Parent constructors are not called implicitly if the child class
defines a constructor. In order to run a parent constructor, a call to
parent::__construct() within the child constructor is required.
As you are doing some work in your parent class constructor, you must invoke it directly in your subclass too (even this would be to only thing you do in child's constructor). I.e.:
class ChildController extends BaseController
{
public function __construct() {
parent::__construct();
}
...

When you extend the controller, I imagine that you're currently doing this:
<?php
class NewController extends BaseController
{
public function __construct()
{
// Do something here.
}
public function detail($action)
{
return $this->foo;
}
}
You see how the __construct method is being overwritten. You can easily fix this by adding parent::__construct() to the beginning of the method, so you'll have this:
<?php
class NewController extends BaseController
{
public function __construct()
{
parent::__construct();
// Do something here.
}
public function detail($action)
{
return $this->foo;
}
}

Related

Why is the parent's constructor being called

I have the simplest bit of code :
Interface
interface iCrudRepository{
public function Create($id);
public function Read($id);
public function Update($id);
public function Delete($id);
}
Parent
class Repository
{
function __construct()
{
echo "SHOULD NOT BE CALLED AUTOMATICALLY";
}
}
Class
require_once(__DIR__.'/../injection/bootstrap.php');
class Admin extends Repository implements iCrudRepository
{
function Create($id)
{
}
function Read($id)
{
}
function Update($id)
{
}
function Delete($id)
{
}
}
$admin = new Admin();
$admin->Create("Something");
The bootstrap class autoloads my classes via the spl_autoload_register function. Since in the Admin class I don't call the parent constructor, it shouldn't execute what is in the parent's constructor right?
The Output
SHOULD NOT BE CALLED AUTOMATICALLY
Probably missing something obvious here but can't quite figure out why it is called.
Docs state:
Parent constructors are not called implicitly if the child class
defines a constructor.
So you have to do this in order to prevent what you are seeing:
class Admin extends Repository implements iCrudRepository
{
public function __construct()
{
}
function Create($id)
{
}
function Read($id)
{
}
function Update($id)
{
}
function Delete($id)
{
}
}

How do you access a child method

How do you access a child method eg.?
class A
{
public function Start()
{
// Somehow call Run method on the B class that is inheriting this class
}
}
class B extends A
{
public function Run()
{
...
}
}
$b = new B();
$b->Start(); // Which then should call Run method
Class A should not try to call any methods that it itself does not define. This will work just fine for your scenario:
class A {
public function Start() {
$this->Run();
}
}
However, it will fail terribly should you actually do this:
$a = new A;
$a->Start();
What you're trying to do here sounds very much like a use case for abstract classes:
abstract class A {
public function Start() {
$this->Run();
}
abstract function Run();
}
class B extends A {
public function Run() {
...
}
}
The abstract declaration will precisely prevent you from shooting your own foot by trying to instantiate and Start A without extending and defining required methods.
If B is inherited from A then B will be like:
class B extends A
{
public function Start()
{
...
}
public function Run()
{
...
}
}
So as Run() and Start() are in the same class, we can call Run() in Start() directly.
public function Start()
{
Run();
}

Constructing objects that extends a super class that has its own constructor

I was unsure what to call this so feel free to edit the title.
I am trying to create my own API. within this API there are certain objects these objects all extends the super class ApiObject:
class ApiObject {
protected $sqltemplate;
public function __construct($db){
$this->sqltemplate = new sqlTemplates($db);
}
protected function getTemplate(){
return $this->sqltemplate;
}
}
Now an example of the objects that extends this class is:
class Group extends ApiObject {
public function __construct(){
}
public function findByUserId(){
}
public function findByTeam(){
}
Now my question is as follow:
When i construct a type of the Group object is the ApiObject's contructor always called? and if so how does it pass the parameter $db to the constructor?
You have all the code, why don't you just try it?
<?php
class ApiObject {
public function __construct($db){
echo __METHOD__, "($db)\n";
}
}
class Group extends ApiObject {
public function __construct(){
echo __METHOD__, "\n";
}
}
new Group;
outputs
Group::__construct
This shows that the constructor of the parent object is not called automatically. You have to do this via parent::__construct($db) and add the $db parameter to the second constructor.
<?php
class ApiObject {
public function __construct($db){
echo __METHOD__, "($db)\n";
}
}
class Group extends ApiObject {
public function __construct($db){
echo __METHOD__, "\n";
parent::__construct($db);
}
}
new Group("db");
outputs
Group::__construct
ApiObject::__construct(db)
For a better understanding: Group::__construct overwrites the parent constructor, that's the reason you have to call it manually. If you don't specify a constructor, the parent constructor is called automatically. Example:
<?php
class ApiObject {
public function __construct($db){
echo __METHOD__, "($db)\n";
}
}
class Group extends ApiObject {
}
new Group("db");
outputs
ApiObject::__construct(db)

PHP class property reference to an object

class Hello {
public function hi() {
echo "Hello, hi!\n";
}
}
class ParentClass {
public $obj;
public function __construct() {
$this->obj = new Hello;
}
}
class Test extends ParentClass {
public function __construct() {
$this->obj->hi();
}
}
$temp = new Test;
The error message I get is "Call to a member function hi() on a non-object". $obj should be referencing to an instance of the class "Hello", but it obviously is not - what am I doing wrong?
You are defining __construct() in your Test class but not calling the parent constructor. If you want the parent constructor to execute, you need to explicitly specify so. Add a call to ParentClass constructor in in Test class constructor.
class Test extends ParentClass {
public function __construct() {
parent::__construct();
$this->obj->hi();
}
}
Also as #Tasos Bitsios pointed in his comment you also need to update your ParentClass constructor as follows:
class ParentClass {
public $obj;
public function __construct() {
$this->obj = new Hello; // Use $this->obj and not just $obj.
}
}
You need call to parent constructor:
class Test extends ParentClass {
public function __construct() {
parent::__construct();
$this->obj->hi();
}
}

How do I get a PHP class constructor to call its parent's parent's constructor?

I need to have a class constructor in PHP call its parent's parent's (grandparent?) constructor without calling the parent constructor.
// main class that everything inherits
class Grandpa
{
public function __construct()
{
}
}
class Papa extends Grandpa
{
public function __construct()
{
// call Grandpa's constructor
parent::__construct();
}
}
class Kiddo extends Papa
{
public function __construct()
{
// THIS IS WHERE I NEED TO CALL GRANDPA'S
// CONSTRUCTOR AND NOT PAPA'S
}
}
I know this is a bizarre thing to do and I'm attempting to find a means that doesn't smell bad but nonetheless, I'm curious if it's possible.
The ugly workaround would be to pass a boolean param to Papa indicating that you do not wish to parse the code contained in it's constructor. i.e:
// main class that everything inherits
class Grandpa
{
public function __construct()
{
}
}
class Papa extends Grandpa
{
public function __construct($bypass = false)
{
// only perform actions inside if not bypassing
if (!$bypass) {
}
// call Grandpa's constructor
parent::__construct();
}
}
class Kiddo extends Papa
{
public function __construct()
{
$bypassPapa = true;
parent::__construct($bypassPapa);
}
}
You must use Grandpa::__construct(), there's no other shortcut for it. Also, this ruins the encapsulation of the Papa class - when reading or working on Papa, it should be safe to assume that the __construct() method will be called during construction, but the Kiddo class does not do this.
class Grandpa
{
public function __construct()
{}
}
class Papa extends Grandpa
{
public function __construct()
{
//call Grandpa's constructor
parent::__construct();
}
}
class Kiddo extends Papa
{
public function __construct()
{
//this is not a bug, it works that way in php
Grandpa::__construct();
}
}
Beautiful solution using Reflection.
<?php
class Grandpa
{
public function __construct()
{
echo "Grandpa's constructor called\n";
}
}
class Papa extends Grandpa
{
public function __construct()
{
echo "Papa's constructor called\n";
// call Grandpa's constructor
parent::__construct();
}
}
class Kiddo extends Papa
{
public function __construct()
{
echo "Kiddo's constructor called\n";
$reflectionMethod = new ReflectionMethod(get_parent_class(get_parent_class($this)), '__construct');
$reflectionMethod->invoke($this);
}
}
$kiddo = new Kiddo();
$papa = new Papa();
I ended up coming up with an alternative solution that solved the problem.
I created an intermediate class that extended Grandpa.
Then both Papa and Kiddo extended that class.
Kiddo required some intermediate functionality of Papa but didn't like it's constructor so the class has that additional functionality and both extend it.
I've upvoted the other two answers that provided valid yet ugly solutions for an uglier question:)
Another option that doesn't use a flag and might work in your situation:
<?php
// main class that everything inherits
class Grandpa
{
public function __construct(){
$this->GrandpaSetup();
}
public function GrandpaSetup(){
$this->prop1 = 'foo';
$this->prop2 = 'bar';
}
}
class Papa extends Grandpa
{
public function __construct()
{
// call Grandpa's constructor
parent::__construct();
$this->prop1 = 'foobar';
}
}
class Kiddo extends Papa
{
public function __construct()
{
$this->GrandpaSetup();
}
}
$kid = new Kiddo();
echo "{$kid->prop1}\n{$kid->prop2}\n";
I agree with "too much php", try this:
class Grandpa
{
public function __construct()
{
echo 'Grandpa<br/>';
}
}
class Papa extends Grandpa
{
public function __construct()
{
echo 'Papa<br/>';
parent::__construct();
}
}
class Kiddo extends Papa
{
public function __construct()
{
// THIS IS WHERE I NEED TO CALL GRANDPA'S
// CONSTRUCTOR AND NOT PAPA'S
echo 'Kiddo<br/>';
Grandpa::__construct();
}
}
$instance = new Kiddo;
I got the result as expected:
Kiddo
Grandpa
This is a feature not a bug, check this for your reference:
https://bugs.php.net/bug.php?id=42016
It is just the way it works. If it sees it is coming from the right context this call version does not enforce a static call.
Instead it will simply keep $this and be happy with it.
parent::method() works in the same way, you don't have to define the method as static but it can be called in the same context. Try this out for more interesting:
class Grandpa
{
public function __construct()
{
echo 'Grandpa<br/>';
Kiddo::hello();
}
}
class Papa extends Grandpa
{
public function __construct()
{
echo 'Papa<br/>';
parent::__construct();
}
}
class Kiddo extends Papa
{
public function __construct()
{
// THIS IS WHERE I NEED TO CALL GRANDPA'S
// CONSTRUCTOR AND NOT PAPA'S
echo 'Kiddo<br/>';
Grandpa::__construct();
}
public function hello()
{
echo 'Hello<br/>';
}
}
$instance = new Kiddo;
It also works as expected:
Kiddo
Grandpa
Hello
But if you try to initialize a new Papa, you will get an E_STRICT error:
$papa = new Papa;
Strict standards: Non-static method Kiddo::hello() should not be called statically, assuming $this from incompatible context
You can use instanceof to determine if you can call a Children::method() in a parent method:
if ($this instanceof Kiddo) Kiddo::hello();
There's an easier solution for this, but it requires that you know exactly how much inheritance your current class has gone through. Fortunately, get_parent_class()'s arguments allow your class array member to be the class name as a string as well as an instance itself.
Bear in mind that this also inherently relies on calling a class' __construct() method statically, though within the instanced scope of an inheriting object the difference in this particular case is negligible (ah, PHP).
Consider the following:
class Foo {
var $f = 'bad (Foo)';
function __construct() {
$this->f = 'Good!';
}
}
class Bar extends Foo {
var $f = 'bad (Bar)';
}
class FooBar extends Bar {
var $f = 'bad (FooBar)';
function __construct() {
# FooBar constructor logic here
call_user_func(array(get_parent_class(get_parent_class($this)), '__construct'));
}
}
$foo = new FooBar();
echo $foo->f; #=> 'Good!'
Again, this isn't a viable solution for a situation where you have no idea how much inheritance has taken place, due to the limitations of debug_backtrace(), but in controlled circumstances, it works as intended.
You can call Grandpa::__construct from where you want and the $this keyword will refer to your current class instance. But be carefull with this method you cannot access to protected properties and methods of current instance from this other context, only to public elements. => All work and officialy supported.
Example
// main class that everything inherits
class Grandpa
{
public function __construct()
{
echo $this->one; // will print 1
echo $this->two; // error cannot access protected property
}
}
class Papa extends Grandpa
{
public function __construct()
{
// call Grandpa's constructor
parent::__construct();
}
}
class Kiddo extends Papa
{
public $one = 1;
protected $two = 2;
public function __construct()
{
Grandpa::__construct();
}
}
new Kiddo();
Funny detail about php: extended classes can use non-static functions of a parent class in a static matter. Outside you will get a strict error.
error_reporting(E_ALL);
class GrandPa
{
public function __construct()
{
print("construct grandpa<br/>");
$this->grandPaFkt();
}
protected function grandPaFkt(){
print(">>do Grandpa<br/>");
}
}
class Pa extends GrandPa
{
public function __construct()
{ parent::__construct();
print("construct Pa <br/>");
}
public function paFkt(){
print(">>do Pa <br>");
}
}
class Child extends Pa
{
public function __construct()
{
GrandPa::__construct();
Pa::paFkt();//allright
//parent::__construct();//whatever you want
print("construct Child<br/>");
}
}
$test=new Child();
$test::paFkt();//strict error
So inside a extended class (Child) you can use
parent::paFkt();
or
Pa::paFkt();
to access a parent (or grandPa's) (not private) function.
Outside class def
$test::paFkt();
will trow strict error (non static function).
<?php
class grand_pa
{
public function __construct()
{
echo "Hey I am Grand Pa <br>";
}
}
class pa_pa extends grand_pa
{
// no need for construct here unless you want to do something specifically within this class as init stuff
// the construct for this class will be inherited from the parent.
}
class kiddo extends pa_pa
{
public function __construct()
{
parent::__construct();
echo "Hey I am a child <br>";
}
}
new kiddo();
?>
Of course this expects you do not need to do anything within the construct of the pa_pa. Running this will output :
Hey I am Grand Pa
Hey I am a child
Ok, Yet another ugly solution:
Create a function in Papa like:
protected function call2Granpa() {
return parent::__construct();
}
Then in Kiddo you use:
parent::call2Granpa(); //instead of calling constructor in Papa.
I think it could work... I haven't test it, so I'm not sure if the
objects are created correctly.
I used this approach but with non-constructor functions.
// main class that everything inherits
class Grandpa
{
public function __construct()
{
$this->___construct();
}
protected function ___construct()
{
// grandpa's logic
}
}
class Papa extends Grandpa
{
public function __construct()
{
// call Grandpa's constructor
parent::__construct();
}
}
class Kiddo extends Papa
{
public function __construct()
{
parent::___construct();
}
}
note that "___construct" is not some magic name, you can call it "doGrandpaStuff".
class Grandpa
{
public function __construct()
{
echo"Hello Kiddo";
}
}
class Papa extends Grandpa
{
public function __construct()
{
}
public function CallGranddad()
{
parent::__construct();
}
}
class Kiddo extends Papa
{
public function __construct()
{
}
public function needSomethingFromGrandDad
{
parent::CallGranddad();
}
}
from php 7 u can use
parent::parent::__construct();

Categories