Hey
In my spare time, I am working on my PHP framework.
Now, to help with development and quickly discover where I miss a type cast, I have adopted to check all parameters that are passed to a method using a function.
For instance:
public function __construct(&$target = null, $depth = 1){
$this->validateArguments(
array(1 => 'int'),
array(1 => $depth)
);
And the code that triggers the exception:
public function testPhpFreakType(){
$obj = 1;
$p = new Xcms_DataStructures_Pointer($obj, "1");
}
0: |--------------------------------------------------|
1: |--Exception: 4cfe2e86ca5970.22624423 - Full Trace |
2: | Tue, 07 Dec 2010 13:54:30 +0100
3: |-Class:
4: | Xcms_Exceptions_InvalidArgument
5: |-Message:
6: | Argument #1 of Xcms_DataStructures_Pointer:__construct() is no _null:int
7: | Stack offset: 3
8: |
9: |-Trace
10: | #0 D:\www\xcms_rev\core\exceptions\invalid.argument.helper.class.php(133): Xcms_Exceptions_InvalidArgumentHelper::factory(1, '_null:int', NULL, 2)
11: | #1 D:\www\xcms_rev\core\basic.class.php(80): Xcms_Exceptions_InvalidArgumentHelper::validateArguments(Array, Array, Array, 1)
12: | #2 D:\www\xcms_rev\core\data.structures\pointer.class.php(49): Xcms_Basic->validateArguments(Array, Array)
13: | #3 D:\www\xcms_rev\core\data.structures\pointer.test.php(73): Xcms_DataStructures_Pointer->__construct(1, '1')
14: | #4 [internal function]: Xcms_DataStructures_PointerTest->testPhpFreakType()
15: | #5 C:\xampp\php\PEAR\PHPUnit\Framework\TestCase.php(737): ReflectionMethod->invokeArgs(Object(Xcms_DataStructures_PointerTest), Array)
16: | #6 C:\xampp\php\PEAR\PHPUnit\Framework\TestCase.php(627): PHPUnit_Framework_TestCase->runTest()
17: | #7 C:\xampp\php\PEAR\PHPUnit\Framework\TestResult.php(629): PHPUnit_Framework_TestCase->runBare()
18: | #8 C:\xampp\php\PEAR\PHPUnit\Framework\TestCase.php(575): PHPUnit_Framework_TestResult->run(Object(Xcms_DataStructures_PointerTest))
19: | #9 C:\xampp\php\PEAR\PHPUnit\Framework\TestSuite.php(766): PHPUnit_Framework_TestCase->run(Object(PHPUnit_Framework_TestResult))
20: | #10 C:\xampp\php\PEAR\PHPUnit\Framework\TestSuite.php(742): PHPUnit_Framework_TestSuite->runTest(Object(Xcms_DataStructures_PointerTest), Object(PHPUnit_Framework_TestResult))
21: | #11 D:\www\xcms_rev\core\testing\manager.class.php(83): PHPUnit_Framework_TestSuite->run()
22: | #12 D:\www\xcms_rev\core\testing\manager.class.php(56): Xcms_Testing_Manager->testClass(Object(ReflectionClass))
23: | #13 D:\www\xcms_rev\cache\pkg\scripting\script_1.php(3): Xcms_Testing_Manager->run(Object(Xcms_Url_DefaultRequest))
24: | #14 D:\www\xcms_rev\core\util.lib.php(340): include('D:\www\xcms_rev...')
25: | #15 D:\www\xcms_rev\core\packages\scripting\controllers\scripting.controller.php(66): Xcms_Util::sandboxedInclude('cache/pkg/scrip...', Array)
26: | #16 D:\www\xcms_rev\core\mvc\controllers\default.controller.php(210): Xcms_Packages_Scripting_Controllers_ScriptingController->execute(Object(Xcms_Packages_Scripting_Models_ScriptModel), Object(Xcms_Templating_Context))
27: | #17 D:\www\xcms_rev\core\mvc\controllers\default.controller.php(170): Xcms_Mvc_Controllers_DefaultController->runScript(1, 0, Object(Xcms_Templating_Context))
28: | #18 D:\www\xcms_rev\core\mvc\controllers\default.controller.php(132): Xcms_Mvc_Controllers_DefaultController->runScripts(0, 0, Array, Array, 1, 0)
29: | #19 D:\www\xcms_rev\index.php(15): Xcms_Mvc_Controllers_DefaultController->run()
30: | #20 {main}
31: |--------------------------------------------------|
I think this speeds up my development quite a bit, because I can catch errors very early in the development process.
I can give multipe possibilities of what is allowed for each parameter, not just a single possibility. Also, it is possible to register custom type/validity-checks on both global and local scope.
One thing I do worry about, however, is the the performance. Of course, I could just make the funciton do nothing in production code, if it takes too much time, or I could write a script to remove all calls to that function.
When I started learning python a while back, the concept to just code to interfaces instead of types seemed very intuitive and made my code much more flexible. Of course that is what I do with PHP as well, but I it's not entirely the same. So now, coming back at my PHP code and having introduced features of static languages such as type checking, I worry about whether that is the right approach.
What are your thoughts on the matter?