Private and protected methods should not be accessed outside the permissible scope of class or subclasses. But there are some situations where this is necessary, for me in some contexts of automated testing (unit or integration), or in others where I am implementing a feature and want to perform punctual executions to verify behaviors.

Regardless of why, and the good practice guideline in which I would claim, do not call private or protected methods outside of their scopes, several languages provide support for this possibility.

In PHP and Java, for example, we can use Reflections (routines that allow us to explore classes structurally).

Example of access to protected methods in PHP

Let’s check out how to run a protected method with private or protected visibility in the PHP language (which can be used in frameworks like Laravel and Symphony).

Our example class is:

class Employee 
{
   private $salary = 1000;

   private function calcBonus() 
   {
      return $this->salary * 0.1;
   }
}

An Employee class with a private method capable of calculating the value of the employee’s bonus.

Using Reflection with PHP

With Reflection we will create a reflection class from the Employee class to extract the calcBonus private method and execute it in sequence:

$reflectionClass = new ReflectionClass(Employee::class);
$reflectionMethod = $reflectionClass->getMethod('calcBonus');
$reflectionMethod->setAccessible(true);
$reflectionMethod->invoke(new Employee()); // '100'

This strategy will work with private or protected methods.

We can refactor this code and access with reflection the desired method without having to instantiate a reflection of the complete class:

$reflectionMethod = new ReflectionMethod(Employee::class, 'calcBonus');
$reflectionMethod->setAccessible(true);
$reflectionMethod->invoke(new Employee()); // '100'

If you need to pass arguments to the method, instead of invoke use ‘ReflectionMethod::invokeArgs’.

Let’s refactor our class so that the calcBonus method receives the calculation factor:

class Employee 
{
   private $salary = 1000;

   private function calcBonus($factor) 
   {
      return $this->salary * $factor;
   }
}

Then we can execute the method by defining the arguments by passing them as an array, in this case even passing a single argument we should send inside the array:

$args = [0.1];
$reflectionMethod->invokeArgs(new Employee(), $args);

Helper funciton to execute protected methods

Finally, add this function as a helper function in your toolbox, making it easier to run protected and private methods in PHP in the future:

/**
 * Calls object method with arguments.
 *
 * @param object $object
 * @param string $method
 * @param array $args
 * @return mixed
 */
function callProtectedMethod(object $object, string $method, array $args = [])
{
    $reflectionMethod = new ReflectionMethod(get_class($object), $method);
    $reflectionMethod->setAccessible(true);
    return $reflectionMethod->invokeArgs($object, $args);
}

Run the helper function as in the following example:

callProtectedMethod(new Employee(), 'calcBonus'); // without arguments

//or

callProtectedMethod(new Employee(), 'calcBonus', [0.2]); // with arguments

Final considerations

If you are testing to validate private methods in classes, it is likely that you have made some mistake in the architecture of this code. Still, this possibility is not ruled out in a strategy I use on a day-to-day basis: I build private methods being executed by direct calls to validate my logic in complexities not yet mastered of the business rule. By doing this I create the possibility to speed up development, and subsequently pull this test code out of my final codebase.

Think about the strategy of use and apply whenever the returned benefits are greater than the pure concept of the technique.