php - class extending alternative - php

I have a main class that I add around a dozen child classes to similar to Example #2.
I'm wondering if there is a better way to accomplish this. I know I could do "extends" on classes (Example #1) however in order to be able to have one variable with access to all extended class functions, I'd have to "daisy chain" the extensions and then create a new class reference on the very last extension - this option is not what I'm looking for.
Example #1:
class main {
function _construct(){}
function main_function1(){}
function main_function2(){}
}
class child1 extends main{
function _construct(){}
function child_function1(){}
function child_function2(){}
}
class child2 extends child1 {
function _construct(){}
function child_function3(){}
function child_function4(){}
}
$main = new child2();
$main->child_function1();
$main->child_function2();
$main->child_function3();
$main->child_function4();
Here is what I'm currently doing.
Example #2:
<?php
class main {
function _construct(){}
function main_function1(){}
function main_function2(){}
}
class child1 {
function _construct($main){$this->main = $main;}
function child_function1(){}
function child_function2(){}
}
class child2 {
function _construct($main){$this->main = $main;}
function child_function3(){}
function child_function4(){}
}
$main = new main();
$main->child1 = new child1($main);
$main->child2 = new child2($main);
$main->child1->child_function1();
$main->child1->child_function2();
$main->child2->child_function3();
$main->child2->child_function4();
?>
Is Example #2 the best way to achieve what I'm looking for?

By doing
class child {
function __construct($main){$this->main = $main;}
}
in Example 2 you would pass the $main instance as a property for child in the constructor. In my opinion this would make sense, if $main is a container that provides information for child - which is useful if you would like to avoid having a constructor with many many arguments. According to your naming, it doesn't look like main is a container. Be aware, that you are creating a dependency between child and main then because if you want to instantiate child, you always need an instance of main in advance! What you are also doing in Example 2 is creating circular references:
$main = new main();
$main->child1 = new child1($main);
$main->child2 = new child2($main);
You would be able to call $main->child1->main then which means a high coupling between main and child. So I'd rather not say "go for Example 2".
In your case it rather sounds like child actually is a special case of main, like the relationship between fruit (main) and apple (child). That makes using extends much more reasonable. You seem to be unsure, because you have many child classes extending main. To me this sound just normal, if all the child classes have a similar purpose and share some basic functionalty which is provided by main. But I'm not quite sure what your goal actually is.

Extending classes can break encapsulation, so depending on your classes it might be best to keep your objects separated as in example #2. You could have a loading function to make setting up the main class easier:
class main {
function load($class){
$this->$class = new $class();
}
}
$main = new main();
$main->load('child1');
$main->child1->child_function1();

In php, You have two options. Either (in 2020) inject your Helper Class in another class as suggested in the first answer or in PHP you can use traits.
Traits are similar to classes but their constructors cannot be public.
It's difficult to use Dependency injection on traits but traits can extend existing classes with methods and they can access the parent methods of their respective classes.
With traits anyway you cannot override the parent methods, you can only add the methods to the stack.
Another downside of traits is that, when you use the parent methods of the containing class, type hinting is not well supported in some IDEs. So in order to get type hinting working you'll need some workarounds.

Related

Can php call a static alias?

In php, is it possible for a method in a parent class to use an alias in a child class from within an instance of the child class?
Parent class:
class ParentClass
{
public function getNewFoo()
{
return new Foo();
}
}
Child class:
use My\Custom\Path\To\Foo;
class ChildClass extends ParentClass
{
}
Code:
$child = new ChildClass();
return $child->getNewFoo();
I would like this code to return a new instance of My\Custom\Path\To\Foo() rather than a new instance of Foo().
I realize I can store the desired path to Foo in a class property, or I can simply instantiate the desired Foo in the child class. However, both of these seem redundant considering the path is already stored in the use statement in the child class.
You're asking a lot of PHP here. It's supposed to know that your use statement is going to impact something in a completely different class, in a completely different file, just because?
If PHP did that by default it would cause a lot of very strange problems for people. Re-define the method, or as you point out, store that property in the class itself.
I think a lot of developers would expect, or at least prefer that PHP behave the way it does.
It sounds like what you need here is a factory function that can be redefined in the subclass to behave differently, or in other words, that getNewFoo() should be overridden in the subclass to use the alternate version.

How would I build a PHP class?

I have a parent class, let's say class main { ... }, and an extension of it, let's call it class extension extends main { ... }.
My question is, how would I build another class, called class messages { ... }, which I can use inside the main class and the extended class of main, extension ? Besides the way I know, calling the class messages like this :
$messages = new messages;
$messages->someMethod();
Is there another way without having to do new ... to make the main and extension class inherit the methods inside the messages class ?
AFAIK, PHP does not support multiple inheritance, as others OOP languages do.
So, no, there is NOT another way.
And yes, you should create a property and instantiate the object inside the main class...
class main {
public $messages; // may be "protected" or "private" instead
public __construct()
{
$this->messages = new messages();
}
public do_something()
{
$this->messages->do_something_else();
}
}
However, there are alternatives to simulate a fake multiple inheritance.
An alternative would be: https://stackoverflow.com/a/356431/370290 - But I don't recommend this (even the own author doesn't).
Another alternative: https://stackoverflow.com/a/358562/370290 - IMHO, as weird as the previous one. :-)
And as of PHP 5.4.0 you can also use traits to achieve a "multiple inheritance" effect: http://php.net/manual/en/language.oop5.traits.php - This is very new at the moment.
You can't extend multiple classes and to exten the main class .. only a good thing if you extend from an abstract class.
But what you could do is add it in the construct of your main class like this:
//member variable for class main
public $_message = null;
public function __construct()
{
$this->_message = new Message();
}
Then whenever you need the message class just call $this->_message + the method you need (eg: $this->_message->addMessage())
don't forget to add this in you subclass:
public function __construct()
{
parent::__construct();
}
The problem you seem to have is that you can't do multiple inheritance (class YourClass extends main, messages).
The common feeling is that if you need multiple enheritance, you're doing something wrong in your design.
Every class is responsible for a single thing. A "extension" in this case "IS A" "main", but it is not a "messages", so it should not be a child of that. IF you need messaging capability, there is no 'shame' at all in just calling it like you suggest: you get yourself a nice object that knows how to message, and play with that. There is no real need to do it differently.
If you're looking for alternatives (which you really don't need as far as I can see!) you could make it a class with a bunch of static methods, and just call it like messages::someMethod(), but I think that would be considered an anti-pattern in this case.
Just go with it: messages are created by an object of type message. So you make one, and call the function. In the end, if you ever need big changes (database connection, logging, etc etc) for you messaging, you can do this all in your nice and cosy messaging class. Everyone happy :)
You should create a class inside a class. Just like in this question.
Then, you can use $this->someclass->function.
Note: construct needs to be $this->someclass = new Whatever() too.

Retrieving data from other classes while extending

First of all I'm very new to OOP and I'm struggling big time. I have a question about the current design of my application and inheritance.
I have a bootstrapper file which initiates all my core classes, after including them, like this:
$security = new Security;
$error_handler = new ErrorHandler;
$application = new Application;
$mysql = new MySQL;
$template = new Template;
$user = new User;
I load the Security and ErrorHandler class first because the Application class needs them first (throw custom 404 errors, make GET variables safe etc). Now all classes extend the Application class, but I can't seem to call any data in any class from a child or parent class.
I read that I need to call the constructor of the parent class first to use any data. That's not really sexy and usefull in my eyes and I don't really see the use of using extends then.
Should I change the design? Or how could I use data from one to another class? I already tried composition but that ended up in a nightmare because I couldn't use any data of different child classes at all.
This is a weird set-up anyhow. You definitely should NOT be using some bootstrapper functionality to preload your classes, especially if certain classes have finite dependencies on other classes. What would be a bit better is this:
Your Security and ErrorHandler classes should use either static methods to allow their functionality to be used without declaring the class OR they should be created as a class var of the Application class.
class Security {
// can be invoked anywhere using Security::somefunction('blah');
public static somefunction($somevar) { ... }
}
OR
require_once('security.php');
require_once('errorhandler.php');
class Application {
public $security;
public $errorHandler;
public function __construct() {
$this->security = new Security;
$this->errorHandler = new ErrorHandler;
}
}
I'm not sure what you mean when you say that you can't access data from any class. Classes should naturally inherit any variables and functions that their parents have declared. So for example:
require_once('application.php');
class User extends Application {
public function throwError($message) {
return $this->errorHandler->somefunction($message);
}
}
Without expressly declaring $this->errorHandler from within the User class, this should still work, as the $errorHandler class var is declared in the Application class.
If you have a child-class that defines a __construct() method, and want its parent's __construct() method to be called, the __construct() method of the child class must call the parent's one.
That's the way it is in PHP ; that's what you must do ; not much of a choice.
As a reference, quoting the Constructors and Destructors section of the manual :
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.

Understanding Classes in PHP

I'm officially mentally retarded. [Let me explain]
I've never really given classes and their relationship any thought until today. I'm trying to figure out something that seems to be pretty obvious but since I'm stupid I can't see it.
Let's say I have a Core Class that will be extended from different files. How can children classes call functions from other siblings (that is if those are considered childs at all).
Sample Code: (don't kill me)
class cOne {
public function functionOne(){
echo "something";
}
}
Then on another file, I say:
class cOneChildOne extends cOne {
public function functionOne(){
echo "something from child one";
}
}
And yet on another file I say:
class cOneChildTwo extends cOne {
public function functionOne(){
echo "something from child two";
}
}
How would I have to create a new object, and when, so that I'm able to access functions from both childs and the parent class in a fashion similar to $newObject->Children->function(); I'm seriously considering the option that I've completely lost my brain today and can't think straight.
I've obviously doing something wrong since: $newObject = new cOne; creates the object but then the code from one of the subclasses is unable to access anything that's not directly in the core class or in itself.
Thanks
You can collect child instances in masters class static array
class C1{
static public $childs=array();
function __construct(){
self::$childs[]=$this;
}
}
class C1C1 extends C1{
function hi(){
echo 'hi from C1C1 <br />';
}
}
class C1C2 extends C1{
function hi(){
echo 'hi from C1C2 <br />';
}
}
$c1 = new C1C2();
$c2 = new C1C2();
$c3 = new C1C1();
$c4 = new C1C1();
$c5 = new C1C1();
$c6 = new C1C1();
foreach(C1::$childs as $c){
$c->hi();
}
The parent class cOne has no knowledge of the classes that extend it in php, so while you can call to the parent from a child class using parent::someFunction(), you cannot call the child classes from the parent. You also could not call functions from other classes that extend cOne from a class that extends cOne, also because cOne has no knowledge of classes that extend it.
You do have a fundamental misunderstanding.
Your two subclasses are different classes with a common ancestor. Each child essentially has knowledge of the parent, but the parent has no knowledge of the children, and the children have no knowledge of each other.
If you want child1 to be able to call methods of child2, then there is something wrong with your design. One solution would be to move the method from child2 to the parent class, so that child1 would also inherit that method.
you can use parent::functionOne(); to call functions of parent class from child class.
you can't call child classes' functions from parent class.
Help me or shoot me!!
Bang!!! =o)=o)=o)
When you create instance of class it only knows its methods and methods from its parents.
There is no way you can tell that there are other class who are extending same parent.
As kgb says, you can't create one object that will give you "access" to both sibling class' behaviour. If you instantiate a cOneChildOne, you'll get something that outputs "something from child one" (*). You could, if you use parent::functionOne(), copy cOne's behaviour, maybe to return "something\nsomething from child one" or whatever.
(*) Don't do this. Rather, return a string:
public function functionOne(){
return "something from child one";
}
This lets you compose your functions, output them to files, etc.
You could always just call cOneChildTwo from inside cOneChildOne statically if this suffices your requirement. $this in a method always points to the callee object (that's how parent::__construct() works), so you could use the callee's state inside cOneChildTwo for extended behaviour.
However, this would possibly imply that you'd require wrapper methods for every sibling's method. This is nothing Reflection can't solve though.
i think you're looking at object inheritance, classes and their relationships the wrong way.. what you've said is not really how inheritance in object oriented programming works. when you want to call a method/function of some other object, may it be an instance of the same class or not, what you need is a reference to that object that you are going to call. the keyword here is pass a reference. the one wanting to call must have a reference to the object it wants to communicate to.
child1.communicateWithAnotherChild(someOtherChild)
Why can't you have a static Array $children in the cOne class, and the __construct() methods for the classes that extend it just call cOne::addChild($this)? They could each implement a getChildren function which sends the request on to the superclass - Shouldn't that work?

How to acess multiple classes through one parent class in PHP

Lets say I have a class called PageBuilder which I instantiate, send parameters to and call functions from through my index file (which acts as a front controller). There are three sub classes associated with the PageBuilder class: Head, Body and Foot, that are accessed by PageBuilder which basically abstracts them for index.
So in theory you could instantiate PageBuilder and have full access to the other classes as if they were part of PageBuilder.
How can I implement a design like this in PHP5 using any combination of classes, abstract classes and interfaces?
I don't think the above is possible with PHP5, not necessarily because PHP has its limitations but maybe because I am going about the design of my application the wrong way.
Common examples of OOP in PHP don't suffice to help me understand how to structure a more complex design.
Thanks.
Some of the other answers are on the right track. The problem you're running into is that your PageBuilder class is doing too much. Just the name sounds wrong for what you're trying to do with it. A PageBuilder sounds like something that would assemble a bunch of parts together into a Page. Let's call these parts Section. Then, what you want to do is use composition, as several of the answers have hinted at.
Inheritance is often described as an is-a relationship, as in if your Section classes extend the PageBuilder class, then a Section is a PageBuilder. What you want though is a has-a relation ship, as in your PageBuilder class has a (or many) Section(s). Any time you need a has-a relationship, you should be looking toward composition rather than inheritance.
So here might be your class hierarchy:
abstract class PageBuilder
{
//#var Section
public $header;
//#var Section
public $body;
//#var Section
public $footer;
public function render()
{
echo $this->header.$this->body.$this->footer;
}
}
class Section
{
protected $content;
}
class LoginPage
extends PageBuilder
{
public function __construct()
{
$this->header=new Section(...);
$this->footer=new Section(...);
$this->body=new Section(...);
}
}
At this point, you're really kind of re-inventing the wheel by making a crappy MVC system. If this is for a project (rather than for learning), you should consider using one of the MVC frameworks for PHP. (I recommend Kohana, but there are several questions regarding the best PHP versions on Stack Overflow.) If you're thinking of these kinds of things, MVC probably won't be a great leap for you.
From what I understand here you could use the composite pattern
http://en.wikipedia.org/wiki/Composite_pattern
Your controller index has only access to an object that implements an interface IPageBuilder (or a name similar), with some standards function like "generatePage". This object would in reality be some kind of container that contain other object of type IPageBuilder. Those leafs object would be able to build some subsection of the page, like Head, Body and Foot. Each of those leaf object would be of a different class, but they will implement the IPageBuilder interface. When your index object call "generatePage", the container will call in order the "generatePage" method of each of its leaf objects, that will in turn take care of rendering the HTML.
Using this approach, if your Body class become too big, you can always turn it into a container that implements the IPageBuilder interface, for example a blog post Body could consist of an Article object and a CommentList object. The body object would then only propagate the "generatePage" method to its children object.
To create your IPageBuilder object, you can use a factory patterns
http://en.wikipedia.org/wiki/Factory_method_pattern
In all honesty, I have tried those kind of approach in the past to generate my HTML and found them to be kind of overkill. My suggestion would be to use a templating engine instead, like Smarty. Your designer will love you (or hate you less) if do that ^^.
http://www.smarty.net/
If you want to know how to use interfaces in PHP, not that it's very hard...
http://ca.php.net/manual/en/language.oop5.interfaces.php
So if I understand correctly you want Head, Body, and Foot to automatically construct as children of PageBuilder?
There are a couple of ways you could maybe do this.
1) Create variables inside of PageBuilder to hold the classes and use a __call method
class PageBuilder{
private _head;
private _body;
private _foot;
function __construct(){
$this->_head = new Head();
$this->_foot = new Foot();
$this->_body = new Body();
}
function __call($name, $args){
if(method_exists($this->_head, $name)) call_user_func_array(array($this->head, $name), $args);
// Repeat for other classes.
}
}
The problem here obviously being if two classes share the same method then the first one to come up wins. You could probably modify it to pick a class based on the function name pretty easily.
2) Chain everything down.
Abstract class Page{
}
class Head extends Page{
}
class Body extends Head{
}
class Foot extends Body{
}
class PageBuilder extends Foot{
}
Either way its somewhat hacked, you just kind of have to make it work.
PHP only allows you to extend one parent class (which can in turn extend another parent class, etc.). There are no interfaces, meaning you can't inherit functions or properties from multiple interfaces as you could in C++.
As such, you will probably need to do something more like this:
class PageBuilder {
protected Head, Body, Foot;
public function __construct($request) {
$view = $this->getView($request);
$this->Head = new PageSection('head.tpl');
$this->Body = new PageSection($view);
$this->Foot = new PageSection('foot.tpl');
}
private function getView($request) {
// #todo return the template filename/path based upon the request URL
}
}
class PageSection {
private $template;
public function __construct($template) {
$this->template = $template;
}
public function render() {
// #todo process and output the $this->template file
}
}

Categories