php,如何防止直接类实例化?

lets say I have a very general class:

class Money
{
    public __construct($actualCountry)
    {
        $this->actualCountry = $actualCountry;
    }

    public function getValute()
    {
        return according to actual country
    }
}

This class needs to be created once, so I have a global factory:

final class Factory
{
    private $money;

    public function getMoney()
    {
        if ($this->money == null)
        {
            $this->money = new Money(Config::getCountryCode());
        }
        return $this->money;
    }
}

and whenever we want to use:

Factory::getMoney()->

but today I saw my colleague trying to do:

(new Money(Config::getCountryCode()))->getValute();

which is obviously wrong, no need multiple occurences. But then how can a class itself say "hey, dont instantize me, use factory"?

I cant set it as singleton, because then everytime:

Money::getInstance(Config::getCountryCode());

is pointless.

But the real problem is not because it may exists multiple - its the way I always have to pass the current country from config. What is Config becames GlobalConfig? Thats why the factory to avoid the lot of parameter passing (what if there will be more parameters to Money?)

If I am getting your drift correctly, What you need is Abstract Class

As you need, an abstract class cannot be initialized directly.

Classes defined as abstract may not be instantiated,.....

There's no way to completely prevent outside instantiation, because for your Factory to work, the constructor will have to be publically reachable, either directly or indirectly.

You can obscure the constructor by making it private, and adding a static factory method to your class:

class Money
{
    private function __construct($actualCountry)
    {
        $this->actualCountry = $actualCountry;
    }

    public static function fromFactory($actualCountry)
    {
        return new static($actualCountry);
    }

    public function getValute()
    {
        // return according to actual country
    }
}

final class Factory
{
    private $money;

    public function getMoney()
    {
        if ($this->money == null)
        {
            $this->money = Money::fromFactory(Config::getCountryCode());
        }
        return $this->money;
    }
}

Or you can alter the constructor to require a (typed) second parameter, this being the factory used. However, this won't work if your factory uses static methods, as it does in your example:

class Money
{
    public function __construct($actualCountry, Factory $factory)
    {
        $this->actualCountry = $actualCountry;
    }

    public function getValue()
    {
        // return according to actual country
    }
}

final class Factory
{
    private $money;

    public function getMoney()
    {
        if ($this->money == null)
        {
            $this->money = new Money(Config::getCountryCode(), $this);
        }
        return $this->money;
    }
}

I think that you should consider again the Singleton pattern. It fits better in the logic you want.

<?php
class Money
{
    private static $instance;

    private function __construct($countryCode)
    {
        #your code here...
    }

    /**
     * Do not include parameter for getInstance.
     * Make the call internally.
     * Now when you have to change Config to GlobalConfig will be painless.
     */
    public static function getInstance()
    {
        if (null === self::$instance) {
            return self::$instance = new Money(Config::getCountryCode());
        }

        return  self::$instance;
    }
}

You can make the constructor private or protected to prevent direct instantiation. (See other answers mentioning the singleton pattern).

If you cannot / don't want to use the singleton pattern you'd have to either accept that the constructor is public or use some closure binding magic to get around it.

Disclaimer: This is just a proof of concept. I wouldn't use it in any production code. There is no nice way to achieve this until PHP supports namespace / class visibility / friend classes.

class Factory
{
    private static $money;

    static function getMoney()
    {
        if (null === self::$money) {
            self::$money = self::createInstance('Money', [Config::getCountryCode()]);
        }

        return self::$money;
    }

    private static function createInstance($class, array $args)
    {   
        // bind a closure to the given class and call it
        return call_user_func(Closure::bind(function () use ($class, $args) {
            // create a new instance without calling the constructor
            $object = (new ReflectionClass($class))->newInstanceWithoutConstructor();

            // call the constructor manually from this context (which has access to it now)
            call_user_func_array([$object, '__construct'], $args);

            // return the constructed object
            return $object;
        }, null, $class));
    }
}

Using the factory:

var_dump(Factory::getMoney());

Output:

object(Money)#3 (1) { ["actualCountry":"Money":private]=> string(10) "some_value" }

Attempting direct instantiation:

Output:

new Money();

Fatal error: Call to private Money::__construct() from invalid context in ... on line ...