8

I'm trying to use constant as a function paramter, is it possible to check type of this constant.

Example of what I want:

class ApiError {
  const INVALID_REQUEST = 200;
}

class Response {
  public function status(ApiError $status) {
    //function code here
  }
}

USE:

$response = new Response();
$response->status(ApiError::INVALID_REQUEST);

This shoud check that given $status is constant of class ApiError. Is something like this possible?

2
  • status(ApiError $status) expects instance of ApiError class not the constant value Commented Jun 17, 2012 at 21:18
  • 1
    I know, that's why i'm asking "How to do it" Commented Jun 17, 2012 at 21:29

5 Answers 5

11

As the others mentioned, there is no generic solution. But if you'd like to do it in a very clean way, model every "object" that you're dealing with (= every possible status), e.g.:

interface ApiError {   // make it an abstract class if you need to add logic
    public function getCode();
}

class InvalidRequestApiError implements ApiError {
    public function getCode() {
        return 200;
    }
}

// Usage:
$response = new Response();
$response->status( new InvalidRequestApiError() );

class Response {
    public function status(ApiError $status) {
        echo "API status: " . $status->getCode();
    }
    // ...
}

This leaves you with a lot of classes, because you encapsulate simple numbers, but also with the ability to type-hint.

Sign up to request clarification or add additional context in comments.

1 Comment

I hate the in_array() proposal because it's array-oriented programming as opposed to object-oriented.
5

You can use in_array() to test against whitelisted values, which is a recommended strategy whenever you need to validate input to a specific value set:

// Test if it is in an array of valid status constants...
$valid_statuses = array(
   ApiError::INVALID_REQUEST, 
   ApiError::INVALID_SOMETHINGELSE, 
   ApiError::STATUS_OK
);
if (in_array($status, $valid_statuses)) {
   // it's an acceptable value
}

To whitelist all constants of a class, you could use reflection and retrieve the constants from ApiError via ReflectionClass::getconstants()

$refl = new ReflectionClass('ApiError');
$valid_statuses = $refl->constants();

Comments

2

An other approach would be to change the call. If we want to check if the const is existing, this line would be too late. $response->status(ApiError::INVALID_REQUEST);

The php interpreter will also check the const for existence and will die with a Fatal Error. That is not catchable using try().

So I would suggest to use string as a parameter to check the existence using defined() and constant()

class ApiError {
  const INVALID_REQUEST = 200;
}

class Response {
  public function status($status) {
    if (!defined('ApiError::'.$status)) {
      return false; // Or throw Exception / other error handling
    }

    $errorCode = constant('ApiError::'.$status);

    //function code here
    return true;
  }
}

The use would then look like this:

$response = new Response();
$response->status('INVALID_REQUEST');

Bad thing is that there is no type hints for this solution.

1 Comment

IMO this is the best answer if you need to keep constants.
1

I like this approach best:

class NoticeType {
    const INFO = 'neutral';
    const WARN = 'alert';
    const FAIL = 'critical';
    const PASS = 'success';
    const LITE = 'brand';

    private $_type;

    function __construct($NOTICE_constant)
    {
        if (!preg_match('/neutral|alert|critical|success|brand/', $NOTICE_constant))
            throw new \Exception('Invalid parameter for '.__CLASS__.' constructor');
        $this->_type = $NOTICE_constant;
    }
    function getType() {
        return $this->_type;
    }
    function __toString() {
        return $this->_type;
    }
    static function INFO () {
        return new NoticeType(self::INFO);
    }
    static function WARN () {
        return new NoticeType(self::WARN);
    }
    static function FAIL () {
        return new NoticeType(self::FAIL);
    }
    static function PASS () {
        return new NoticeType(self::PASS);
    }
    static function LITE () {
        return new NoticeType(self::LITE);
    }
}

Usage is very straight-forward and you would have to go out of your way to mess up:

function test (NoticeType $n) {
    echo ($n == NoticeType::INFO)."\n";
}

test (NoticeType::INFO());

Comments

0

SplEnum could help. Example from PHP docs:

class Month extends SplEnum {
    const __default = self::January;

    const January = 1;
    const February = 2;
    const March = 3;
    const April = 4;
    const May = 5;
    const June = 6;
    const July = 7;
    const August = 8;
    const September = 9;
    const October = 10;
    const November = 11;
    const December = 12;
}

echo new Month(Month::June) . PHP_EOL;

try {
    new Month(13);
} catch (UnexpectedValueException $uve) {
    echo $uve->getMessage() . PHP_EOL;
}

Output:

6
Value not a const in enum Month 

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.