You can see this is a somewhat debatable topic. This is my take:
Type Hinting
Use type hinting when possible. Type hints are not possible in PHP for primitive types, so yes, you should check to ensure you've received valid arguments. If you have not, your function can throw an Exception or return some default value like null or false.
Defensive Programming
The idea of writing testable code is that failures are not silent or mysterious. There's no reason to avoid explicit argument validation: be verbose and your code is more clear and usable.
On top of validating your arguments, you can implement an error handler to catch the edge cases. But you should be validating most arguments, especially if they have an effect on persistent data (like your database).
Murphy's Law is in full effect, therefore you must contend with as many predictable bugs as you can. An invalid argument is an easily predictable bug -- failure to validate it is a timebomb in your code. Calling is_string
, for example, is easy and diffuses the bomb.
Boxing
Another consideration is to "box" your variables. This leads to very verbose code, but it does have the advantage of allowing type hints for primitives.
I've never seen anyone actually do this though their entire codebase, but it is out there. There are SPL classes available for primative types, so you'd wind up like this:
function stringThing (\SplString $myString) { ... }
stringThing(new \SplString('This is my string'));
SplTypes enforce the primitive type and throw exceptions when it is misused. From the documentation:
$string = new SplString("Testing");
try {
$string = array(); // <----------this will throw an exception
} catch (UnexpectedValueException $uve) {
echo $uve->getMessage() . PHP_EOL;
}
SplTypes is a PECL extension, and not always a part of a standard PHP install, so check your extensions before using it. The extension is also considered experimental, though it has been in around for some time now.
You can also create your own box fairly simply:
class myStringBox {
private $string = '';
public function __construct($string=null) {
if ($string)
$this->set($string);
}
public function set($val) {
if (!is_string($string)) throw new \InvalidArgumentException();
$this->string= $val;
}
public function __toString() {
return $this->string;
}
public function trim() { return trim($this->string); } // extend with functions?
}
... but this has a major functional difference in that you cannot directly set a new string value like this:
$stringBox = new myStringBox('hello world! ');
echo $stringBox; // "hello world![space]"
echo $stringBox->trim(); // "hello world!"
$stringBox = 'A new string';
echo $stringBox->trim(); // Error: Call to a member function trim() on a non-object
Instead, you have to use a setter method:
$stringBox = new myStringBox('hello world! ');
echo $stringBox; // "hello world![space]"
echo $stringBox->trim(); // "hello world!"
$stringBox->set('A new world');
echo $stringBox->trim(); // "A new world"
This all leads us back to type hinting, which is probably the most efficient way to NOT have to validate your arguments.
Related Reading
- Spl types - http://www.php.net/manual/en/book.spl-types.php
- Type hinting in PHP - http://php.net/manual/en/language.oop5.typehinting.php
- Defensive programming - http://en.wikipedia.org/wiki/Defensive_programming