Home » Php » php – Avoiding magic numbers without creating dependencies

php – Avoiding magic numbers without creating dependencies

Posted by: admin July 12, 2020 Leave a comment

Questions:

I’m creating an error manager for an API I’m work on. The idea is that it provides a single store of error codes that can be returned from the API, ensuring that the same error in different calls is handled in the same way (e.g. required value missing from the request).

My initial approach was along the lines of:

$this->_errorManager->setError(ErrorCodes::REQUIRED_FIELD);

However this creates a dependency on the error codes class anywhere I want to set an error.

The alternative is:

$this->_errorManager->setError(100);

But now I’ve got a number sitting in the middle of my code that means nothing.

While I can think of solutions to this specific problem there will be other situations where I will want to use an ‘enum’ and I can’t think of a solution that doesn’t tightly couple the classes.

Is there a better way of doing this or a different approach I can take to remove magic numbers? Or is the tight coupling something I just have to accept and consider on a case by case basis?

How to&Answers:

This is desired coupling. While it is a good idea, to have the application and its error manager loosely coupled, there is no reason to separate the application and its error codes, they belong together.

Dependencies:

+-----------------------+
|Application error codes|<------------+
+-----------------------+             |
           ^                          |
           |                          |
+----------+----------+               |
|Application component|               |
+----------+----------+               |
           |                          |
           v                          |
+-----------------------+     +-------+-----+
|Error handler interface|<|---+Error handler|
+-----------------------+     +-------------+

Answer:

You can clear some of these hurdles with “preprocessor” macros and a makefile. The preprocessor macros come courtesy of m4.

Assume you maintain a file of error codes like this.

   define(`ERR_REQUIRED_FIELD',`100')dnl

Then you can write your PHP code with the English error “constant”.

$this->_errorManager->setError(ERR_REQUIRED_FIELD);

And include a line in your makefile that runs these two files through m4. There’s more than one way to manage that. (For brevity, I’m omitting the makefile, and just running my test file through m4.)

$ m4 test.php.m4 > test.php
$ cat test.php
$this->_errorManager->setError(100);

This does introduce a dependency; the php files will all depend on the file of error codes. But it’s a trivial dependency that’s easily managed through the makefile. In practice, I’d probably build a file of error codes that looks like this . . .

ERR_DISK_FULL
ERR_REQUIRED_FIELD
ERR_MISSING_ARG

and use text utilities and make to either

  • build the m4 macro definitions, or
  • build the definitions for your ErrorCodes module.

The numeric values equal the line numbers; this guarantees you never have a duplicate error code.