tags:

views:

63

answers:

5

Given that my class looks like this:

class Methods{
    function a(){
        return 'a';
    }

    function b(){  
        $this->a();   
    }

    function c(){ 
        $this->a();
    }  
}

Is it possible to ensure that function a can only be called from function b?

In the above example function c should fail. I could just include it in function b, but in the future I may want to let a() be called by some new functions (e.g. d() or e())

+5  A: 

Start by learning the difference between public, private and protected methods... it's useful to have at least a grasp of OOP basics before wanting to do something incredibly complicated like this. Yes, it's possible using debug_backtrace() to identify where the call to the method was made from; but it's a very big overhead.... and I see no value in actually setting such a restriction.

Mark Baker
A: 

Not really.

  • You could check the caller by checking the result of debug_backtrace()
  • You can make it private to avoid it being called from outside the class, and then move c() outside of the class.
Sjoerd
+2  A: 

You should first have a look at class visibility modifiers, like Mark Baker has suggested. That is probably what you're looking for.

However, if it's not, the following code should work for you:

class Methods
{
    private function a()
    {
        $bt = debug_backtrace();
        if(!isset($bt[1]) || $bt[1]['function'] != 'b' || $bt[1]['class'] != get_class($this))
        {
            //Call not allowed
            return NULL;
        }
    }
    function b()
    {
        //allowed
        $this->a();
    }
    function c()
    {
        //not allowed
        $this->a();
    }
}
Tim Cooper
That code really smells... it's a good solution though.
Cristian
A: 

I see no point in restricting methods inside the same class to call other methods.

Maybe your model is wrong and you have to create two classes? One class should be one logical unit (somehow).

If you use separate classes, you can use the private keyword on method a and it can't be called from outside the class anymore.

Felix Kling
+1  A: 

The closest thing to what you ask for is a closure (aka anonymous function) within the method you want to restrict it to. Closures are not accessible outside that method they are defined in. These are generally used to define callbacks and passed to other methods, but you can invoke it directly.

class Methods{
  function b(){
    $a = function() {
      return 'a';
    }; // don't forget the trailing ';'

    $a();   
  }

  function c(){ 
    $this->a(); // fails
  }  
}

Making a method private or protected will prevent it from being called from outside the class, but will not restrict which methods inside the class have access to it. At some level you need to trust your code to follow the rules of use for your API.

Classes are generally the unit encapsulation for trust and if you make the method private from outside use, and document it, you should be able to trust that it is used properly from within the class. If not, perhaps that class has gotten too big and it's time to refactor.

As @Sjoerd mentions, you could also inspect the call stack, but agree with @Mark Baker that there is little to no value in this; it's akin to abuse of the language and makes your code a mess as well.

Chadwick