Home / Section index
 www.icosaedro.it 
PHPLint
Reference
Manual

Contents
Introduction
Basic features
Packages
Importing modules
Importing packages
Namespaces
Constants
Global variables
Types
Arrays
Control structures
Functions
Type compatibility
Typecasting
Predefined constants
Predefined superglobals
Classes
Recursive declarations
Errors
Exceptions
PHPLint's Std. Library
Autoloading classes
Definite assignment analysis
PHP4 - Classes
PHP4 - Type conversion operators
Documentator
Usage
How To...
Reserved keywords
To-do list
Memorandum
License
References
Syntax
<= ExceptionsAutoloading classes =>

Contents of this chapter

    PHPLint's Standard Library

      Handling errors -- errors.h

      Autoloading classes -- autoload.php

      The typecast magic function -- cast.php

      Include all -- all.php

PHPLint's Standard Library

PHPLint comes with its own library of real PHP code named PHPLint Standard Library. These libraries provide features intended to be strictly tight to the PHPLint validator. These libraries are available under the stdlib/ directory of the PHPLint package.

Handling errors -- errors.h

The stdlib/errors.php sets the error log level to the maximum value and maps errors, warnings and notices into exceptions, to be more precise into ErrorException. This provides two benefits:

  • Errors can be now managed with only one tool, that is the try/catch statements. Note that ErrorException is checked, so you must choose to either handle these errors, or declare them as thrown by the function or method. This improves the safety of the program because it is garanteed the error is handled somewhere.
  • Protects the program against the access to missing entries in arrays. In fact, by default under PHP accessing an unexisting array element produces a simple E_NOTICE, altought this error might have severe conseguences on the safety of the program. Moreover, selecting an invalid entry generates NULL as value, which might bring to unexpected errors several statement later, making debugging more difficult. So detecting these events may be really important for the safety of the whole program.

The following example illustrates how simple can become error handling of I/O functions using exceptions:

require_once "stdlib/errors.php";

$fn = "doesNotExist.txt";
try {
    $f = fopen($fn, "r");
    $content = fgets($f, filesize($fn));
    fclose($f);
}
catch( ErrorException $e ){
    echo $e->getMessage(), ", using default empty content.\n";
    $content = "";
}
echo $content;

=> WARNING [2] fopen(doesNotExist.txt): failed to open stream:
   No such file or directory in /home/salsi/test.php:18, using
   default empty content.

The following example illustrates what happen accessing an invalid index of an array:

$a = array("zero", "one", "three");
echo $a[0];
echo $a[1];
echo $a[2];
echo $a[3];
=> Uncaught exception 'ErrorException' with message
   'WARNING: Undefined offset: 3 in /home/salsi/test.php:13'

If you are unsure if a certain entry of an array does exist of not, you must then use the function array_key_exists($key, $array).

Autoloading classes -- autoload.php

This package contains the magic __autoload($class) which is invoked automatically by PHP (and then by PHPLint too) in order to resolve unknown classes. Using this package you don't need to require_once every class your source require, as this is performed automatically by PHP at runtime. PHPLint applies this algorithms also to classes that appear in the meta-code, in DocBlocks and in the cast() function.

This package should be located in the root directory of all your PHP sources as the path of the path of the class it contruct is made relative to the directory where the package autoload.php resides:

const SRC_BASE_DIR = __DIR__;

/*. unchecked .*/ class AutoloadException extends Exception {}

/*. void .*/ function __autoload(/*. string .*/ $name)
{
    /*. pragma 'autoload' './' '/' '.php'; .*/
    $fn = (string) str_replace("\\", "/", $name) . ".php";
    if( ! is_readable($fn) )
        throw new AutoloadException("__autoload($name): file $fn does not exist or not readable");
    require_once $fn;
}

The SRC_BASE_DIR constant can also be used to load packages that are not bare classes:

require_once SRC_BASE_DIR . "/mylib/mypkg.php";

To improve the safety of yours programs, this package also checks that the proper php.ini file had been loaded, that is the php.ini file that resides in the root directory.

The final structure of the PHP's source directory might then look similar to this one:

(PHP's sources root)
|-- all.php
|-- autoload.php
|-- cast.php
|-- errors.php
|-- php.ini
|-- com
|   `-- acme
|       |-- framework
|       |   `-- ...
|       |-- utils
|       |   `-- ...
|       `-- website
|           `-- ...
`-- it
    `-- icosaedro
        |-- bignumbers
        |   |-- BigFloat.php
        |   `-- BigInt.php
        |-- examples
        |   |-- FunnyMessages.php (class it\icosaedro\examples\FunnyMessages)
        |   |-- User.php (class it\icosaedro\examples\User)
        |   |-- cast-test.php
        |   |-- err-test.php
        |   `-- serialize-test.php
        `-- utils
            |-- Floats.php (class it\icosaedro\examples\Floats)
            |-- Floats-test.php
            |-- Integers.php (class it\icosaedro\examples\Integers)
            |-- Integers-test.php
            |-- Strings.php (class it\icosaedro\examples\Strings)
            `-- Strings-test.php

The typecast magic function -- cast.php

This package provides the cast() magic function that performs a runtime check over the type of an expression, and then return its value only if it matches the expected type and throws an exception if don't match. In other words, a statement of this form

$x = cast(T, EXPR);

tells to PHPLint that the final result of the expression must be of type T; moreover, at runtime the cast() function will check that the type of the expression V be of the expected type T, otherwise a CastException is thrown. Note that this function does not performs conversions of values, but merely checks the type of V agains the type T.

To be more precise the first argument of the cast(T,V) function must be a string (or any static expression giving a string as a result) that describes the expected type, then including boolean, int, float, string, resource, user defined classes and arrays. It is important to note that classes defined inside a namespace must be indicated with their absolute or fully qualified name:

require_once "cast.php";
use it\icosaedro\utils\BigInt;
use it\icosaedro\utils\BigFloat;
...
if( $n instanceof BigInt )
    $bi = cast("it\\icosaedro\\utils\\BigInt", $n);

else if( $n instanceof BigFloat )
    $bf = cast("it\\icosaedro\\utils\\BigFloat", $n);

As first concrete example, we see how this function can be used to validate user's submitted parameters:

$name = cast("string", $_GET["name"]);

As we already know, $_GET["name"] can be a string, an array or even it can do not exist at all. If the error handler we see above is loaded, an exception will be thrown if this element of the $_GET[] array does not exist. Moreover, an exception will be raised by cast() if it exists but it is not a string. The final result is that the variable $name will get the expected type of value, and an error (which is fatal in this simple example) is detected and signaled otherwise. In the same manner we can acquire entire arrays:

if( isset($_GET["selected_boxes"]) )
	$selected_boxes = cast("array[int]string", $_GET["selected_boxes"]);
else
	$selected_boxes = /*.(array[int]string).*/ array();

It is very important to note that the formal typecast /*.(array[int]string).*/ is allowed by PHPLint only if applied to the empty array() or to the NULL constant, and it is not allowed in any other case.

The cast() becomes really useful dealing with some complex libraries that return generic containers of object, so there is the problem of how to extract these objects while checking also their type, and making happy PHPLint too. Here is an example with the DOM library:

/*. void .*/ function process_children(/*. DOMNode .*/ $root)
{
    $children = $root->childNodes;
    foreach($children as $elem){
        $node = cast("DOMNode", $elem);
        switch($node->nodeType){

        case XML_ELEMENT_NODE:
            $node_element = cast("DOMElement", $elem);
            process_children($node_element, $level+1);
            break;

        ...
    }
}

$dom = new DOMDocument();

$dom->load("dom-test.xml");

$root = $dom->documentElement;

process_children($root);

As a general rule, cast("CLASS", expr) returns a value of type CLASS only if expr is NULL or it is an instance of CLASS, otherwise it throws CastException. Note that if the value is NULL, NULL is returned by the function, so if you are expecting values that may be NULL you must check this value separately either with if( $value === NULL ) or with if( is_null($value) ).

The syntax of the type accepted by cast() can be described in EBNF form as follows:

type = "boolean" | "int" | "float" | "string" | "resource"
	| "object" | CLASS_NAME | array_type;

array_type = "array" [ index_type { index_type } type ];

index_type = "[]" | "[int]" | "[string]";

Note that there is not a "mixed" type, as this type does not really exists in PHP (there is no a is_mixed() function) but it is purely fictional in PHPLint. Here object matches any instance of a class, while CLASS_NAME is the name of any existing class. Note too that the abbreviation bool and the alternate names integer real double are not allowed to make faster the tests the cast() must perform at runtime.


cast(T,V) Type of the expression V
boolean int float string array resource CLASS mixed
T "boolean" OK(b) NO NO NO NO NO NO OK(a)
"int" NO OK(b) NO(e) NO(d) NO NO NO OK(a)
"float" NO NO(f) OK(b) NO(d) NO NO NO OK(a)
"string" NO(g) NO(h) NO(h) OK(b) NO NO NO(i) OK(a)
"array..." NO NO NO NO OK(j) NO NO OK(j)
"resource" NO NO NO NO NO OK(b) NO OK(a)
"CLASS" NO NO NO NO NO NO OK(c) OK(a)

Legenda:
a) code("T",mixed) performs runtime check on the actual type of the mixed expression, and performs unboxing of simple types boolean, int and float.
b) cast("T",T) is unuseful has PHPLint already has detected the type of the expression.
c) In cast("CLASS", $obj) $obj must be NULL or an instance of the class CLASS.
d) To convert a string representing a number into number use the PHP's typecast operators (int) and (float).
e) To convert float into int you may use the PHP's typecast operator (int).
f) To convert int into float you may use the PHP's typecast operator (float).
g) To convert boolean into string you may use this espression: ((V?) "TRUE" : "FALSE").
h) To convert int or float into string you may use the PHP's typecast operator (int) and (float). The function sprintf() provides a finer control on the result.
i) Objects that implements the __toString() method can be converted into string either using the PHP's (string) typecast operator or calling directly that method. That method is invoked automatically for objects that appear in string concatenation and inside the echo statement. j) As a general rule, cast("array[I]E",V) matches only V of type mixed that at runtime is NULL or an array of the specified exact type, or a generic array of unspecified index type and elements that at runtime has the exact specified type. The discussion below details how this match is performed.


Arrays have a semanthic much more articulated. First of all there is the type of the index. The empty index [] meas that the intended array can have indexes that can be both integer numbers and strings, while [int] matches only arrays whose indexes are all integer numbers, and [string] matches only arrays whose indexes are strings. If a type for the elements of the array is specified, then all the elements of the array must match that type.

NULL values match any string, resource, array and object.

In the following examples, the result of the cast() magic function is always exactly a value of the type specified, although in some cases this value at runtime might be also NULL according to the type model of PHPLint for types that are "dynamically" allocated; for simple types (boolean, int and float) NULL is never returned:

cast("boolean", $expr)
$expr must be either boolean or mixed (that is, a boxed boolean). At runtime, if $expr is NULL or does not contain a boxed boolean, a CastException is thrown.

cast("int", $expr)
$expr must be either int or mixed (that is, a boxed int). At runtime, if $expr is NULL or does not contain a boxed int, a CastException is thrown.

cast("float", $expr)
$expr must be either float or mixed (that is, a boxed float). At runtime, if $expr is NULL or does not contain a boxed float, a CastException is thrown.

cast("string", $expr)
$expr must be either string or mixed (that holds a string). At runtime, $expr must be either NULL or string, otherwise a CastException is thrown.

cast("resource", $expr)
$expr must be either resource or mixed (that holds a resource). At runtime, $expr must be either NULL or resource, otherwise a CastException is thrown.

cast("object", $expr)
$expr must be either an object of any class, or mixed (that holds an object). At runtime, $expr must be either NULL or object, otherwise a CastException is thrown.

cast("CLASS_NAME", $expr)
$expr must be either an instance of the CLASS_NAME, or any of it derived classes, or mixed (that holds an object). At runtime, $expr must be either NULL or an object derived from CLASS_NAME, otherwise a CastException is thrown.

cast("array", $expr)
$expr must be either NULL, an empty array, an array of any type, or mixed (that holds an array). At runtime, $expr must be either NULL or an array of any structure, otherwise a CastException is thrown.

cast("array[]", $expr)
The same as array.

cast("array[int]", $expr)
$expr must be either NULL, an empty array, an array with integer indexes and elements of any type, or mixed (that holds an array[int]). At runtime, $expr must be either NULL, an empty array, or an array with integer indexes, otherwise a CastException is thrown.

cast("array[]int", $expr)
$expr must be either NULL, an empty array, an array with any type of indexes and elements of type integer, or mixed (that holds an array[]int). At runtime, $expr must be either NULL, an empty array, or an array with any indexes but whose elements are all int, otherwise a CastException is thrown.

cast("array[int]string", $expr)
$expr must be either NULL, an empty array, an array with integer indexes and string elements, or a mixed (that holds array[int]string). an array). In this case the matching rules applies recursively, so any single element of the array matches just what string matches, that is either NULL or string. NULL entries should be checked with array_key_exists($key, $array) for existance. At runtime, $expr must be either NULL, an empty array, or an array with int indexes and whose elements are string (or NULL), otherwise a CastException is thrown.

cast("array[int][int]CLASS_NAME", $expr)
$expr must be either NULL, an empty array, a matrix of CLASS_NAME, or a mixed (that holds array[int][int]CLASS_NAME). Here too, any single element of the array can be NULL, then some of the entries given by the first index may be NULL just like as some entries of the second index may be NULL. At runtime, $expr must be either NULL, an empty array, or an array with int indexes and whose elements are etc. etc., otherwise a CastException is thrown.

Include all -- all.php

Finally, the all.php package simply loads all the packages above, so providing full support for class autoloading, safe error handling and safe typecasting in your programs.



<= ExceptionsAutoloading classes =>

Umberto Salsi

Contact
Site map
Home / Section index