1

I got a doubt while doing this:

class Logger {
        public static $log_INFO = 'INFO';
        public static $log_ERROR = 'ERROR';
        public function log($logLevel, $param2, $param3) {
              // Write log to some file
        }
}

class Midea {
       public function fn1 {
           $logger = new Logger();
           $logger->log(Logger::$log_INFO, 'some', 'some2');
       }
}

Now my question is: Is there any way to make the log function in Logger class to accept only the static variables (any static variable) of Logger class? It should not accept any other string or integers as arguments.

xdazz
  • 158,678
  • 38
  • 247
  • 274
Jebin
  • 702
  • 13
  • 33
  • See the answer here : http://stackoverflow.com/questions/6568857/possible-to-test-if-a-variable-is-static-in-php – Julien May 21 '12 at 07:14
  • My code could work if you make one of the following decisions: a) all log level properties will be prefixed with "log_"; or b) all log level properties will have their own property name as values. In case a) I can change the code to get the correct ReflectionProperty, in case b) the code is already correct. – Mihai Stancu May 21 '12 at 07:27

3 Answers3

3

My answer was based on the fact that $logLevel contains the name of a static class property.

If you use it as the updated example Logger::$INFO, that will pass the value string(4) "INFO" and this will not work. it needs to pass the value string(8) "log_INFO"

Yes, by using reflection:

public function log($logLevel, $param2, $param3) {
    $reflection_property = new ReflectionProperty(get_called_class(), $logLevel);
    if($reflection_property->isStatic()) {
        // rest of the code
    }
}

IMO this kind of enforcement is unnecessary, it adds both complexity and overhead to the code. And the benefits are small.

Coding your necessity like this seams more appropriate to me:

public static function $log_levels = array('INFO', 'ERROR');
public function log($log_level, $param2, $param3) {
    if(in_array($log_level, static::$log_levels)) {
        // code
    }
}

The structure above opens up a neat opportunity:

public static function $log_levels = array(
    'INFO' => array('Logger', 'handleInfoLogs'),
    'ERROR' => array('Logger', 'handleErrorLogs')
);
public function log($log_level, $param2, $param3) {
    if(array_key_exists($log_level, static::$log_levels)) {
        return(static::$log_levels[$log_level]($param2, $param3));
    }
}
Mihai Stancu
  • 15,848
  • 2
  • 33
  • 51
  • Thanks for the clarification. I agree with your answer. Can you explain me why should we add "log_" as prefix for this case? – Jebin May 21 '12 at 09:33
  • for the last case (the array of levels with functions to handle each level) there is no need for the prefix. – Mihai Stancu May 21 '12 at 12:36
  • the need for the prefix is present when creating a new ReflectionProperty object, the constructor takes $class_name and $property_name as arguments. So we need the value of Logger::$SomeLoggingLevel to contain its exact name "SomeLoggingLevel", if they all use the same prefix such as "log_" we can call new ReflectionProperty($class_name, "log_".$property_name), hence the value of Logger::$log_INFO has to be exactly "INFO" (because we'll add the prefix when we create the ReflectionProperty) – Mihai Stancu May 21 '12 at 12:39
1

What you are asking for is akin to enums in the Java world. Check this question on SO, which has some information on how you can implement similar concepts in PHP.

More specifically, you could implement what you are asking for like this:

class Logger {
    const INFO = 1;
    const ERROR = 2;
};

You could then use it in code like:

Logger::INFO

It isn't perfect, but I believe it is as close as it gets in PHP. To make it bullet-proof, you would have to employ some reflection to check the arguments passed in. This answer on SO has more information on how you can go about implementing it.

Community
  • 1
  • 1
Jeshurun
  • 22,940
  • 6
  • 79
  • 92
  • It's true, enums would be more efficient in here. – Mihai Stancu May 21 '12 at 07:13
  • 1
    The downside here is that this passes the value of Logger::INFO (which is **int(1)**) weakness that can be abused. – Mihai Stancu May 21 '12 at 07:17
  • Correct, so implementing class would have to combine this with some reflection trickery to validate that the argument passed is valid. [This](http://stackoverflow.com/questions/1528280/how-to-implement-enum-like-functionality-in-php) question on SO is related. – Jeshurun May 21 '12 at 07:21
  • I've skimmed through that response and without adding a type hinting to the parameter this is not feasible with reflection alone. – Mihai Stancu May 21 '12 at 07:24
1

It's quite cumbersome but you could do this:

abstract class LoggerStatus
{
    public function __toString()
    {
        return $this->status;
    }
}

class LoggerStatusInfo extends LoggerStatus
{
    protected $status = 'INFO';
}

class LoggerStatusError extends LoggerStatus
{
    protected $status = 'ERROR';
}

class Logger {
    public static $log_INFO;
    public static $log_ERROR;

    public function __construct()
    {
        self::$log_INFO = new LoggerStatusInfo();
        self::$log_ERROR = new LoggerStatusError();
    }

    public function log(LoggerStatus $logLevel, $param2, $param3) {
          // Write log to some file
    }
}

I've never attempted this myself but I don't see any reason it wouldn't work. Personally, I'd go for something simpler.

Okonomiyaki3000
  • 3,628
  • 23
  • 23