Jump to content

Issue extending class


Mad_Griffith

Recommended Posts

Hi, I can't understand what I am doing wrong. It keeps on loading endlessly. Can you help out?

I have one file with this:

require_once 'path/to/firstclass';

$Core = new FirstClass();

Then in second file I have this:

require_once 'SecondClass.php';

class FirstClass {

public function __construct() {
	$SecondClass = new SecondClass();
}

}

In a third file I have this:

class SecondClass {

public function __construct() {
	require_once 'path/to/thirdclass';

	$ThirdClass = new ThirdClass();
	$ThirdClass->secondMethod();
}

public function firstMethod() {
	echo 'my first method!';
}

}

And in a fourth file I have this:

class ThirdClass extends SecondClass {

public function secondMethod() {
	$this->firstMethod();
}

}

Thank you.

Edited by Mad_Griffith
Link to comment
Share on other sites

Would the ThirdClass be inheriting the SecondClass' constructor, and infinitely trying to make new instances of ThirdClass?

Edited by Funce
Link to comment
Share on other sites

You're right, that's the issue. How can I avoid this in such a way that I am not forced to put an empty constructor in ThirdClass? Should I just use a check on the class in the SecondClass' constructor or is there a better solution? 

Edited by Mad_Griffith
Link to comment
Share on other sites

No worries, but if you put a check in SecondClass, you're undermining the point of using classes. It makes SecondClass on its own (and anything else that inherits from it) have more baggage.

Link to comment
Share on other sites

The constructor is only inherited if you don't define one, so the solution is to define a constructor.  If you have a constructor and want to call the parent constructor explicitly you can use parent:: for that.  That is often the case, but the parent constructor is not called automatically because sometimes you want to parent constructor to run either before or after the child constructor, so that behavior is left up to the programmer to do explicitly.

So the behavior you are expecting is the default behavior when you have a constructor.  Therefore, it sounds like the solution is to make a constructor.

Link to comment
Share on other sites

uhm, I get your points. What do you think of this solution? firstMethod() is actually just a init function containing stuff that SecondClass won't share with any other class.

 

    public function __construct()
    {
        if (get_class($this) !== 'SecondClass') return;

        $this->firstMethod();
    }

 

Edited by Mad_Griffith
Link to comment
Share on other sites

I just noticed I am in a conundrum. in firstMethod() I am also setting the value of a few SecondClass' variables that I want to be accessible in ThirdClass, but which of course is not set in ThirdClass if I either add the check in the SecondClass' constructor or override the constructor in ThirdClas. How do I overcome that?

Thank you.

Edited by Mad_Griffith
Link to comment
Share on other sites

Hi, I am stuck in a conundrum.

I have the following code:

class Dad {

	public function setup() {
		// sets object and local vars
	}

	public function init() {
		$sonInstance = new $sonName();
		$sonInstance->$methodName();
	}

	public function __construct($sonName = null, $methodName = null) {
		$this->setup($moduleName, $methodName);
	}

}

class Son extends Dad {

	public function doSomething() {

	}

}

All this complication is needed because I need to have Dad() flexible enough to call Son() dynamically and be also able to inject the Son's class and method directly (please note that I omitted all the getters and setters on purpose from the code above).

$Dad = new Dad();
$Dad->init();
$Son = new Dad('Son', 'doSomething');
$Son->init();

And I need Son extending Dad so that I can access Dad's methods within Son.

But doing all this also makes Dad->setup() be called twice. How can I avoid this? What pattern suggestions do you have?

Thank you.

Edited by Mad_Griffith
Link to comment
Share on other sites

If you don't want to run a function when you call the constructor, then you can't run that function when you call the constructor.  This code is a little too abstract to say why you wouldn't want to call the function more than once, but maybe just call it explicitly instead of in the constructor.  Maybe use a static property to tell whether or not it's already been called.  Maybe use a parameter that determines whether it should be called.

Link to comment
Share on other sites

This is a more faithful code. I need to instantiate Module only once because it can be extended for an indefinite number of times. I hope you can shed some light as I am currently stuck.

<?php

class Site extends Module {

    public function indexAction() {
        echo 'init\'ed!';
    }
}

class Module {
    public $name;

    public function getName() {
        return $this->name;
    }

    public function setName($name) {
        $this->name = $name;
    }

    public function getMethod() {
        return $this->method;
    }

    public function setMethod($method) {
        $this->method = $method;
    }

    public function init() {
        $this->setName('Site');
        $this->setMethod('indexAction');

        $moduleName = $this->getName();
        $methodName = $this->getMethod();

        $moduleInstance = new $moduleName();
        $moduleInstance->$methodName;
    }

    public function __construct() {
        $this->init();
    }
}

$Module = new Module();
Edited by Mad_Griffith
Link to comment
Share on other sites

I'm a little confused why you're doing it that way.  If the only thing the constructor does is call a single method, why isn't that method the constructor?  And there's no reason to set and then immediately get the value again.  Also, if those are parameters it seems like it would be a little more flexible.

class Module {
    public $name;

    public function __construct($module, $method) {
        $this->setName($module);
        $this->setMethod($method);

        $moduleInstance = new $module();
        $moduleInstance->$method;
    }

    public function getName() {
        return $this->name;
    }

    public function setName($name) {
        $this->name = $name;
    }

    public function getMethod() {
        return $this->method;
    }

    public function setMethod($method) {
        $this->method = $method;
    }
}

class Site extends Module {

    public function __construct() {
        parent::__construct('Site', 'indexAction');
    }
}

$site = new Site();

Now, what's the issue you were trying to describe before?  Are you saying you want multiple module instances but for some reason you only want one of them to instantiate a site instance?

This seems a little backwards also.  Class A extends class B, but you create an instance of class A inside class B.  You're creating an instance of an extended class inside the class that gets extended.  What's the point of that?  I don't see a reason to do that, why not just instantiate a single instance of site?  Why are you explicitly instantiating module at all if you've extended it?

Link to comment
Share on other sites

And why are you doing that from the superclass and not the child class?

I still have no idea why you would instantiate a child class inside a superclass.  I don't know what the purpose is.  I have never heard of anyone doing that, I haven't even heard of a use case for it.

If you think about classes extending other classes, there are multiple analogies.  Maybe you have a "food" class.  Then you extend the food class to make a "fruit" class.  Then you extend the fruit class to make an "apple" class.  You're talking about creating an instance of apple from inside the general food class and that makes no sense at all to me why you would want to do that.  Why is everything of type "food" required to do something with an apple?  If I'm creating an object for rice, or for eggs, why are they messing with apples?  It doesn't make sense, the way that's organized does not make sense.  Object-oriented programming should be extensible, reusable, and flexible, and when you're creating an instance of a child class inside a superclass you're violating one or more of those goals.

The major reason why it doesn't make sense is because the child class presumably implements a set of methods or properties that the superclass does not.  That's the point of extensibility.  The superclass doesn't know anything about those additional methods or properties.  So why does it make sense for the superclass to create an instance of that object and then try to use methods or properties that were not defined in the superclass?  Why am I creating an instance of a Food object which immediately tries to remove seeds that might not even be there?

Link to comment
Share on other sites

If your design goal is to minimize the lines of code in the child class, you're going to end up with a bloated parent class.

Maybe you're thinking of some version of a factory pattern where you have a factory class that creates other classes based on what you pass to it.  Look into that and see if it applies, but I would recommend not doing anything for any child class inside a parent class.  Your goal should be to keep the parent class (and all classes) clean and easy to understand.  If you tie things up in a way where you're calling methods from child classes inside parent classes then you're going to make debugging more difficult and you're starting to introduce requirements in your classes which will degrade the reusability and flexibility goals of OOP.

Or, at a minimum, move that code which calls some initialization function to the child's constructor instead of the parent's constructor, so that each child class can do whatever it needs to be done.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...