2

In an effort to avoid magic numbers and a bit of future-proofing, i'd like to be able to declare a single constant or variable with multiple constituent elements, to enable a single point to change the values in future.

For example

$myPdf->setFillColor(88, 38, 123) # using this method many times in a routine.

Now the stakeholders want to change the background colour of the pdf (long after requirements sign-off...) so there are many places to change this rgb value. The method setFillColor($r, $g, $b) is from a third party component so I can't change the method to accept a single array argument.

Is there a way to declare a single construct which will unpack into the three, individual, required arguments for the setFillColor() method so something like the following is possible?

$my_color = [88, 38, 123];
$myPdf->setFillColor($my_color);
John Conde
  • 217,595
  • 99
  • 455
  • 496
Pedro del Sol
  • 2,840
  • 9
  • 39
  • 52

2 Answers2

2
define('FOO', [1, 2, 3]);

function f($a, $b, $c) {
    var_dump($a, $b, $c);
}

f(...FOO);

See https://3v4l.org/EGfFN.

If you cannot use the ... operator because you're using an ancient version of PHP, you can also use call_user_func_array:

call_user_func_array([$myPdf, 'setFillColor'], MY_COLOR)

For PHP versions < 7 you can't set the constant to an array, you'll have to use a variable instead.

deceze
  • 510,633
  • 85
  • 743
  • 889
0

There's 2 approach to your question.

First of all, let me show you a quote from Clean Code book of Robert C Martin (Chapter 3: Functions. Functions Arguments - Arguments Objects, page 43):

When a function seems to need more than two or three arguments, it is likely that some of those arguments ought to be wrapped into a class of their own.

As I can see, your value represents a RGB color. Why don't just wrap it as a class?

class RGB
{
    private $blue;
    private $green;
    private $red;

    public function __construct($red , $green , $blue)
    {
        $this->red = $red;
        $this->green = $gree;
        $this->blue = $blue;
    }

    /** others necesary methods **/
}

And just use as you want:

$my_color = new RGB(88, 38, 123);
$myPdf->setFillColor($my_color);

And if you need use others kind of colors system, just use an interface:

interface Color { }

RGB implements Color

class RGB implements Color

And a new color system:

class CMYK implements Color
{
    private $cyan;
    private $magenta;
    private $yellow;
    private $black;

    public function __construct($cyan , $magenta , $yellow , black)
    {
        $this->cyan = $cyan;
        $this->magenta = $magenta;
        $this->yellow = $yellow;
        $this->black = $black;
    }
}

The PDF method just need accept an class which implements Color:

public function setFillColor(Color $color)

The second approach, it's not well for Object Oriented, but is using the function argument syntax for PHP >= 5.6 or call_user_func_array to pass a variable number of parameters. Which I can't recommend in your example (for other purpose can be a good ideia), but it exists.

Gabriel Heming
  • 1,100
  • 10
  • 30
  • @RyanVincent It's possible and much more. But I wouldn't do this. Because you're removing the purpose of the class exists (a function can do the same thing). When you encapsulate a bunch of variables into a class you're giving a reason/purpose to that class exists. After that, a class can behave as the code needs (just need to fit with the SOLID paradigm) – Gabriel Heming Dec 21 '16 at 14:46
  • @RyanVincent And not, that not easy to understand or being flexible. for OOP the most flexible in this case is use an interface. Other patterns as decorator can be used for flexibility – Gabriel Heming Dec 21 '16 at 14:48