PHP: Access Method in sub-class - php

I want to know how to access a method i a sub-class of a class when I'm in another sub-class of that same class...
For example:
class foo {
}
class bar extends foo {
public function something() {
//do something here
}
}
class soap extends foo {
$this->something(); //This is the method I wanna call...
}
As you can see I wanna access a subclass's method from another sub class.
How do I do this in PHP?

You can do it directly, but only if soap is also a subclass of bar:
class soap extends bar {
public function someFunction()
{
$this->something(); // This will work
}
}
If it's not, you still have an option: obtain an instance of bar and then call the method on it:
class soap extends foo {
public function someFunction(bar $bar)
{
$bar->something(); // This will also work
}
}
Barring that, there's not much else you can do. Since bar is not in soap's inheritance chain, there is no way to reference something using only $this from within any of soap's methods.

Related

Is it possible to cancel function override in parent class and use function from top level parent

class TopParent
{
protected function foo()
{
$this->bar();
}
private function bar()
{
echo 'Bar';
}
}
class MidParent extends TopParent
{
protected function foo()
{
$this->midMethod();
parent::foo();
}
public function midMethod()
{
echo 'Mid';
}
public function generalMethod()
{
echo 'General';
}
}
Now the question is if I have a class, that extends MidParent because I need to call
class Target extends MidParent
{
//How to override this method to return TopParent::foo(); ?
protected function foo()
{
}
}
So I need to do this:
$mid = new MidParent();
$mid->foo(); // MidBar
$taget = new Target();
$target->generalMethod(); // General
$target->foo(); // Bar
UPDATE
Top parent is ActiveRecord class, mid is my model object. I want to use model in yii ConsoleApplication. I use 'user' module in this model, and console app doesn't support this module. So I need to override method afterFind, where user module is called. So the Target class is the class that overrides some methods from model which uses some modules that console application doesn't support.
Try this (http://php.net/manual/en/language.oop5.final.php - not allow to overriding in the childrens):
final protected function foo()
{
$this->midMethod();
parent::foo();
}
in class MidParent and the class Target can't overrides this method.
Directly - you can't. This is how OOP works.
You can do it by a little redesign, e.g. in MidParent add method:
protected function parentFoo()
{
parent::foo();
}
and in Target:
public function foo()
{
$this->parentFoo();
}
But, again, this is only a workaround to solve your question and not a solution.
Actually, you can do this like this way with Reflection::getParentClass():
class Foo
{
public function test($x, $y)
{
echo(sprintf('I am test of Foo with %s, %s'.PHP_EOL, $x, $y));
}
}
class Bar extends Foo
{
public function test()
{
echo('I am test of Bar'.PHP_EOL);
parent::test();
}
}
class Baz extends Bar
{
public function test()
{
$class = new ReflectionClass(get_class($this));
return call_user_func_array(
[$class->getParentClass()->getParentClass()->getName(), 'test'],
func_get_args()
);
}
}
$obj = new Baz();
$obj->test('bee', 'feo'); //I am test of Foo with bee, feo
-but this is an architecture smell in any case. If you need something like this, that should tell you: you're doing something wrong. I don't want to recommend anyone to use this way, but since it's possible - here it is.
#AnatoliyGusarov, your question is interesting and in a sense you can achieve what you desire using yii and php advances features like Traits and Traits in Yii.
Given that it depends on what version of php you are using.However in yii you can achieve this by behaviors and check this SOQ.
In a nutshell you have to use language advanced features or YII framework features to come around this kind of issues,but that boils down to actual requirements

How to call a overrided method in child, on the parent class

I've got a class
class foo {
function do_something() {
load();
}
function load() {
//things
echo 'load from foo';
}
}
And another class that extends foo (a child class):
class bar extends foo {
function load() {
//things
echo 'load from bar (child)';
}
}
And then:
$obj = new bar();
What I want to know is how can I call $obj->do_something() such that the method uses the child 'load' method instead of the method declared in the foo class.
So, I want the output to be:
$obj->do_something();
Output: load from bar (child)
Is this possible with PHP?
Thanks!
You need to qualify the object context with $this. Unlike some other languages, PHP requires that you qualify the instance explicitly with $this for all method calls from within an object.
class foo {
function do_something() {
// load();
$this->load();
}
function load() {
echo 'load from foo';
}
}
class bar extends foo {
function load() {
echo 'load from bar (child)';
}
}
$obj = new bar();
$obj->do_something();
In your code (merely calling load()) the language was looking for a globally defined function named load, which of course wouldn't work (or in worse cases, would but incorrectly)
As another answer points out, you must similarly qualify static methods though the use of self or static (which I would suggest you read up on to understand the binding differences)
From an inheriting class, in an overriding method, you can also use parent to invoke the parent classes' definition of the method:
class bar extends foo {
function load() {
parent::load(); // right here
echo 'load from bar (child)';
}
}
This will invoke the parent's version of the load method, and continue execution with the child classes' definition.
I would recommend use abstract function if you want to have such a tight coupling of methods. it's going to require high maintenance and you are creating some tight couplings between classes.
i would recommend creating an abstract function in the parent that each of the children will implement with it's own logic.
Even then if you want change your parent class function to this
function do_something(){
if(method_exists($this, 'test')){
$this->test();
}
}
you can use abstract class and abstract method:
abstract class Foo{
function test() {
$this->method();
}
abstract function method();
}
class Test extends Foo {
function method() {
echo 'class Test';
}
}
$test = new Test();
$test->test();
Try this
class foo {
function do_something() {
static::load();
}
function load() {
//things
echo 'load from foo';
}
}
class bar extends foo {
function load() {
//things
echo 'load from bar (child)';
}
}
$obj = new bar;
$obj->do_something();

Object of class A cannot be create directly but only by class B

class A
{
public function foo()
{
}
}
class B
{
$a = new A;
public function go()
{
}
}
I want A object cannot be created directly.But only by class B.
How i can do this.
Why would you need that?
Remember - a class is a defacto factory for objects, and the object should do things, and it should do them with passed params and available instance variables which means you should pass everything the object needs to the constructor and you should not care about the fact that the object can be created by everybody.
Seriously.
Sounds like you want to extend an abstract class.
abstract class A {
protected function foo() {
echo "Hello world!";
}
}
class B extends A {
public function go() {
$this->foo();
}
}
$obj = new B;
$obj->foo(); // error - cannot call a protected method directly
$obj->go(); // echo's "Hello world!"
If you really want to do this, check factory design pattern. I think it will what you are asking for. There we will have a separate factory class for managing object creation.

Require a method in parent class to be called in PHP

As the title states, I'm trying to make a method in a parent class required. Although, I suppose it could be any class. For instance:
class Parent
{
function foo ()
{
// do stuff
}
}
class Child extends Parent
{
function bar ()
{
// do stuff after foo() has ran
}
}
Basically, I want foo() to be required to run or Child class doesn't run and returns an error or redirects to a different page. I could call the function, but I'm wondering If I can make it a requirement when extending the parent class.
If you leverage abstract classes and methods, you can force subclasses to implement the missing methods.
abstract class ParentClass
{
public function foo ()
{
// do stuff
$this->bar();
}
abstract protected function bar();
}
class Child extends ParentClass
{
protected function bar()
{
// does stuff
}
}
Subclasses that don't implement bar() will generate a fatal error.
What you should probably do is override Parent::foo() and then call the parent method in the overridden method like so:
class Parent
{
function foo ()
{
// do stuff
}
}
class Child extends Parent
{
function foo ()
{
if(!parent::foo()) {
throw new Exception('Foo failed');
}
// do child class stuff
}
}
Why not just set a boolean in function foo() that acts as a flag. Check to see if it has been set in the child class/functions, and you're all set.
Have the child call the function from the parent in the construct.
class Child extends Parent
{
function bar ()
{
// do stuff after foo() has ran
}
function __construct(){
parent::foo();
}
}
As already mentioned, it sounds like you want foo() to be abstract, forcing child classes to override it.
Any class containing an abstract class in PHP requires your parent class to be abstract too. This means it can't be instantiated (constructed), only derived / sub-classed. If you try to instantiate an abstract class the compiler will issue a fatal error.
http://php.net/manual/en/language.oop5.abstract.php
See the code in Peter Bailey's answer.
If you're not actually initializing any code within parent class you should use an object interface. Interface methods have to be implemented or the script will throw a fetal error.
More information on them can be found: http://us3.php.net/interface.
I think this might be the only way of implementing such functionality, as I don't think there is a built in solution.
class Parent
{
public $foo_accessed = FALSE;
function foo ()
{
$this->foo_accessed=TRUE;
// do stuff
}
}
class Child extends Parent
{
function bar ()
{
if($this->foo_accessed==TRUE) {
// do stuff after foo() has ran
} else {
// throw an error
}
}
}
Do not depend on other methods. Make sure they've ran.
class Parent
{
function foo()
{
// do stuff
}
}
class Child extends Parent
{
private function bar()
{
// do child class stuff
}
public function doFooBar()
{
parent::foo();
$this->bar();
}
}
Following approach will only ever complain after all processing has been done - however if that is fair to you it will definately make sure foo() has been called in the parent class or otherwise trigger a condition that you can act upon.
class DemandingParent {
private $hasFooBeenCalled = false;
public function foo() {
$this->hasFooBeenCalled = true;
/* do Stuff */
}
public function __destruct() {
if (!$this->hasFooBeenCalled) {
throw new Exception("Naughty Child! Call your parent's foo b4 you speak up!");
}
}
}

How to call super in PHP?

I have a classB which extends classA.
In both classA and classB I define the method fooBar().
In fooBar() of classB I want to call fooBar() of classA at the beginning.
Just the way I'm used to, from Objective-C. Is that possible in PHP? And if so, how?
parent::fooBar();
Straight from the manual:
The ... double colon, is a token that allows access to ... overridden properties or methods of a class.
...
Example #3 Calling a parent's method
<?php
class MyClass
{
protected function myFunc() {
echo "MyClass::myFunc()\n";
}
}
class OtherClass extends MyClass
{
// Override parent's definition
public function myFunc()
{
// But still call the parent function
parent::myFunc();
echo "OtherClass::myFunc()\n";
}
}
$class = new OtherClass();
$class->myFunc();
?>
Just a quick note because this doesn't come up as easy on Google searches, and this is well documented in php docs if you can find it. If you have a subclass that needs to call the superclass's constructor, you can call it with:
parent::__construct(); // since PHP5
An example would be if the super class has some arguments in it's constructor and it's implementing classes needs to call that:
class Foo {
public function __construct($lol, $cat) {
// Do stuff specific for Foo
}
}
class Bar extends Foo {
public function __construct()(
parent::__construct("lol", "cat");
// Do stuff specific for Bar
}
}
You can find a more motivating example here.

Categories