Last Updated: February 25, 2016
·
7.947K
· eviweb

How emulates private class concept in PHP

As PHP only provides public context for class declaration, here is a way to emulate the concept of private class (in action in PrivateClass::__construct) :

/**
 * The private class
 */
final class PrivateClass
{
    /**
     * defines the only class able to instantiate the current one
     * 
     * @var string
     */
    private $allowedConsumer = 'AllowedPrivateClassConsumer';

    /**
     * constructor
     * 
     * @throws Exception
     */
    public function __construct()
    {
        /**
         * here comes the privacy filter, it could be extracted to a private method
         * or to a static method of another class with few adjustments
         */
        $builder = debug_backtrace();
        if (count($builder) < 2 || 
            !isset($builder[1]['class']) ||
            $builder[1]['class'] !== $this->allowedConsumer)
        {
            throw new Exception('Need to be instantiated by '.$this->allowedConsumer);
        }
    }
}

/**
 * The only allowed consumer of the private class
 */
final class AllowedPrivateClassConsumer
{
    private $privateclass;
    public function __construct()
    {
        $this->privateclass = new PrivateClass();
    }
}

/**
 * the following consumer will make the private to throw an exception
 */
final class NotAllowedPrivateClassConsumer
{
    private $privateclass;
    public function __construct()
    {
        $this->privateclass = new PrivateClass();
    }
}

/**
 * the following class encapsulate the allowed consumer
 */
final class AllowedPrivateClassConsumerEncapsulator
{
    private $allowedconsumer;
    public function __construct()
    {
        $this->allowedconsumer = new AllowedPrivateClassConsumer();
    }
}

/**
 * the following function will make the private to throw an exception
 */
function notAllowedFunction()
{
    return new PrivateClass();
}

/**
 * these throw an Exception
 */
//$myvar = new PrivateClass();
//$myvar = new NotAllowedPrivateClassConsumer();
//$myvar = notAllowedFunction();

/**
 * this works great
 */
//$myvar = new AllowedPrivateClassConsumer();
//$myvar = new AllowedPrivateClassConsumerEncapsulator();