3

here is the class structure. I want Observer:callme() to be callable from Children too.

class Observer
{
    protected callme()
    {
    }
}

class Parent extends Observer
{
    function createChild()
    {
        $this->callme(); // this is OK
        return new Child ($this);
    }
}

class Child
{
    private $this myParent;
    public function __constructor ($myParent)
    {
        $this->myParent = $myParent;
    }

    public function __destroy()
    {
        $this->myParent->callme(); // FAIL!
    }
}

so how to make FAIL work? (without making it public, because its only for used inside "Parent" and its "Children")

John Smith
  • 6,129
  • 12
  • 68
  • 123
  • 2
    Why is it protected if you want to access it publicly? Just make it public like it should be. – John Conde Sep 11 '15 at 17:52
  • because its only for used inside "Parent" and its "Children" – John Smith Sep 11 '15 at 17:53
  • 2
    That's not a child unless you extend the parent. – John Conde Sep 11 '15 at 17:55
  • 1
    In your example, `Child` is not in the same class hierarchy as `Observer` and `Parent` therefore it cannot call `Observer::callme()`. Your class names suggest that you mean for `Parent` to be the superclass for `Child` but that is not what the code says. – Josh J Sep 11 '15 at 17:59
  • 3
    Instantiating a new `Child` object inside of `Parent` doesn't make `Child` a child of `Observer`, thus the protected method `callme()` is not availble inside of it... – BenM Sep 11 '15 at 17:59
  • 1
    [You might wanna look at this.](http://stackoverflow.com/questions/4361553/php-public-private-protected?rq=1) [And this.](http://stackoverflow.com/questions/419844/best-to-use-private-methods-or-protected-methods?rq=1) – GiamPy Sep 11 '15 at 17:59
  • if you wish call method that was not extended then you need to use this solution :: https://stackoverflow.com/questions/17174139/can-i-how-to-call-a-protected-function-outside-of-a-class-in-php/70462175#70462175 – pankaj Dec 23 '21 at 12:35

4 Answers4

3

The problem is that a protected method is only accessed from the same class or the class children. What you can do is extend your Child class from Parent, like this:

class Child extends Parent
{
    public function __constructor ()
    {
        parent::__constructor();
    }

    public function __destroy()
    {
        $this->callme(); // Should work!
    }
}

Or just change the method to public.

And, btw, is this code some kind of real code that you will use? That constructor receiving the parent object seems to be so wrong. What are you trying to accomplish?

Yam Frich
  • 77
  • 3
  • yes, thats okay, but this architechture is not like that. There can be only one "Parent" and many of "Child"-ren. "Child" is not really a "child", its rather a contained object – John Smith Sep 11 '15 at 18:11
  • 1
    Why don't you share your real code or at least a better idea of what you want to do, there are many experienced developers here that can help you with the architecture, including myself :D – Yam Frich Sep 11 '15 at 18:21
2

protected means that you can call that method only from the same class and from subclasses. What you want to do is not possible. The protected keyword would be pointless if you could call these methods from everywhere.

In C++ there is the friend keyword to achieve what you want: you could define Child as friend of Observer (this has to be done from within Observer), and then you can call all methods in Observer (including private and protected) from within methods of Child. But such a keyword does not exist for PHP.

Michael
  • 6,451
  • 5
  • 31
  • 53
1

My comment on your question explains why it doesn't work. This answer shows a way to accomplish what you asked based upon your clarification that MyChild should not extend MyParent.

This is a hack example that makes it work by exploiting the fact that php doesn't care if you call protected methods on other instances than yourself as long as you share the ancestor of the protected method.

I had to change the code some to make it valid php. __constructor is not the name of a php constructor.

hacky.php

<?php

class Observer
{
    protected function callme()
    {
        echo 'I was called from ' . get_called_class(), PHP_EOL;
    }
}

class MyParent extends Observer
{
    public function createMyChild()
    {
        $this->callme(); // this is OK
        return new MyChild ($this);
    }
}

class MyChild extends Observer // hackey extends
{
    private $myMyParent;
    public function __construct($myMyParent)
    {
        $this->myMyParent = $myMyParent;
        $this->myMyParent->callme();
    }
}

$p = new MyParent;
$c = $p->createMyChild();

Result:

$ php hacky.php
I was called from MyParent
I was called from MyParent
Josh J
  • 6,813
  • 3
  • 25
  • 47
0

I think I found the solution:

class Parent extends Observer
{
    function createChild()
    {
        $this->callme(); // this is OK
        return new Child (function() { $this->callme(); });
    }
}

class Child
{
    private $gatewayFunction;
    public function __constructor (Closure $gatewayFunction)
    {
        $this->gatewayFunction = $gatewayFunction;
    }

    public function __destroy()
    {
        $this->gatewayFunction->__invoke();
    }
}

Who is going to crap himself? :)

John Smith
  • 6,129
  • 12
  • 68
  • 123