views:

44

answers:

4

Is there a way to add more than one type hinting to a method? For example, foo(param) must receive a instance of string OR bar OR baz. Thank you.

+2  A: 

Type hinting only allows for one hint per parameter (and also, the hint needs to be array or a class name, you can't hint string), but you can do this by checking the type of the param within your function, using get_class:

function foo($param)
{
  if (!(is_string($param) || in_array(get_class($param), array("Bar", "Baz")))
  {
    // invalid type for $param!
  }
}

You could even use trigger_error to have it fail with a PHP error (like it would if a type hint failed) if you wanted.

Daniel Vandersluis
I'd suggest throwing a `InvalidArgumentException`, so that you can at least attempt to recover from the error...
ircmaxell
@ircmaxell I was just demonstrating how the OP *could* replicate how type hints work.
Daniel Vandersluis
@Daniel: I'm not saying not to `trigger_error`. It all depends on your style (and there's nothing wrong with using `trigger_error`). I prefer exceptions, so I use `InvalidArgumentException`. If your goal is to mimic type hints, then by all means trigger a fatal error...
ircmaxell
@ircmaxell Agreed; I personally wouldn't use `trigger_error` for this either :)
Daniel Vandersluis
+3  A: 

That is not possible to enforce (except inside the method). You can only provide a single type hint, and only to objects/interfaces and arrays (since PHP 5.1).

You can/should however document it in your method, i.e:

/**
 * @param string|Bar|Baz $param1
 */
function foo($param1);
PatrikAkerstrand
+1 for documentation
Hannes
+1  A: 

This is one use of interfaces. If you want to be sure that the object has a ->foobar($baz) method, you could expect an interface:

interface iFooBar {
    public function foobar($baz);
}

class Foo implements iFooBar {
    public function foobar($baz) { echo $baz; }
}
class Bar implements iFooBar {
    public function foobar($baz) { print_r($baz); }
}

function doSomething(iFooBar $foo) {
    $foo->foobar('something');
}

Then, when calling, these will work:

doSomething(new Foo());
doSomething(new Bar());

These will not:

doSomething(new StdClass());
doSomething('testing');
ircmaxell
Pretty cool! There are SPL types too (experimental): http://pl.php.net/manual/en/book.spl-types.php
joao
the same way i'd done it.
ITroubs
@joao: SPLTypes won't work on 5.3 (They use deprecated c calls). Plus the last update was in 2008, so it's pretty safe to say it's not current...
ircmaxell
A: 

Fantastic question. It applies to both IDE documentation and PHP 5 Type Hinting. You have to remember that in OO polymorphism is your friend.

If you create a base class and extend them, your type hint will be base class... all extended class will work. See example below.

//
$test = new DUITest();

//  Calls below will work because of polymorphism
echo $test->test(new Molecule()) . '<br/>';
echo $test->test(new Vodka()) . '<br/>';
echo $test->test(new Driver()) . '<br/>';
echo $test->test(new Car()) . '<br/>';

//  Will not work because different data type
echo $test->test(new Pig()) . '<br/>';
echo $test->test(new Cop()) . '<br/>';
echo $test->test('test') . '<br/>';
echo $test->test(array()) . '<br/>';



/**
 * Class to test 
 */
class DUITest {

    public function __construct() {
        ;
    }

    /**
     * Using type-hinting
     * 
     * See below link for more information
     * @link http://www.php.net/manual/en/language.oop5.typehinting.php
     * 
     * @param Molecule|Car|Driver|Vodka $obj 
     */
    public function test(Molecule $obj) {
        echo $obj;
    }

}

/**
 * Base Class
 */
class Molecule {

    public function __construct() {}

    /**
     * Outputs name of class of current object
     * @return <type> 
     */
    public function __toString() {
        return get_class($this);
    }

}

class Car extends Molecule {}

class Driver extends Molecule {}

class Vodka extends Molecule {}

class Pig {}
class Cop extends Pig{}
Alex