views:

332

answers:

7

PHP, as we all know is very loosely typed. The language does not require you to specify any kind of type for function parameters or class variables. This can be a powerful feature.

Sometimes though, it can make debugging your script a painful experience. For example, passing one kind of object into a method that expects a different kind of object can produce error messages complaining that a certain variable/method doesn't exist for the passed object. These situations are mostly annoyances. More onerous problems are when you initialize one object with an object of the wrong class, and that "wrong object" won't be used until later on in the script's execution. In this case you end up getting an error much later than when you passed the original argument.

Instead of complaining that what I passed doesn't have a specific method or variable, or waiting until much later in script execution for my passed in object to be used, I would much rather have an error message, at exactly where I specify an object of the wrong type, complaining about the object's type being incorrect or incompatible.

How do you handle these situations in your code? How do you detect incompatible types? How can I introduce some type-checking into my scripts so that I can get more easily understood error messages?

Also, how can you do all this while accounting for inheritance in Php? Consider:

<?php
class InterfaceClass
{
#...
}

class UsesInterfaceClass
{
   function SetObject(&$obj) 
   {
       // What do I put here to make sure that $obj either
       // is of type InterfaceObject or inherits from it       

   }
}
?>

Then a user of this code implements the interface with their own concrete class:

<?php

class ConcreteClass extends InterfaceClass
{
}



?>

I want ConcreteClass instances, and all future, unknown user-defined objects, to also be acceptable to SetObject. How would you make this allowable in checking for the correct type?

+11  A: 

Actually for classes you can provide type hinting in PHP (5+).

 <?php
 class UsesBaseClass
 {
      function SetObject(InterfaceObject $obj) 
      {
      }
 }
 ?>

This will also work correctly with inheritance as you would expect it to.

As an aside, don't put the word 'object' in your class names...

Eran Galperin
+4  A: 

as an addition to Eran Galperin's response you can also use the type hinting to force parameters to be arrays - not just objects of a certain class.

<?php
class MyCoolClass {
   public function passMeAnArray(array $array = array()) {
      // do something with the array  
   }  
 }  
 ?>

As you can see you can type hint that the ::passMeAnArray() method expects an array as well as provide a default value in case the method is called w/o any parameters.

arin sarkissian
+1  A: 

@Eran Galperin's response is the preferred method for ensuring the object you are using is of the correct type.

Also worth noting is the instanceOf operator - it is helpful for when you want to check that an object is one of multiple types.

leek
instanceof is useful. Just remember not to abuse it.
phjr
A: 

You can set the error_reporting ini setting in your php.ini file or use error_reporting function to set it in run time

Ahmad
+1  A: 

You see, there are multiple answers about type hinting. This is the technical solution. But you should also make sure that the whole design is sensible and intuitive. This will make type problems and mistakes more rare.

Remember that even these type failures will be thrown at runtime. Make sure you have tests for the code.

phjr
A: 

Even in the case you describe, your script will crash, complaining there is no method / attribute X on the object Y so you'll know where does this come from.

Anyway, I think that always try to prevent grew up programmers to pass the wrong object to a method is not a good time investment : you could spend it in documenting and training instead.

Duck typing and careful colleagues is what you need, not additional checks that will make you app more rigid.

But it may be a Pythonista point of view...

e-satis
+1  A: 

For primitive types you could also use the is_* functions :

public function Add($a, $b)
{
  if (!is_int($a) || !is_int($b))
    throw new InvalidArgumentException();
  return $a + $b;
}
Andrei Rinea