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
<= Definite assignment analysisPHP4 - Type conversion operators =>

Contents of this chapter

    PHP4 - Classes

      New attributes for class items

      Class constants

      Properties

      Methods

      Example

      Overriding properties

      Overriding methods

      Special methods

      Final classes

      Abstract classes

PHP4 - Classes

PHP4 classes declare properties and methods. PHPLint extends the syntax of the PHP 4 classes adding the visibility attributes (public, protected and private), abstract, final and static. Since these attributes are not allowed by PHP 4, they can be specified either through the PHPLint meta-code or through a DocBlock comment. In the examples that follow we will use the PHPLint meta-code because it is shorter. PHPLint uses these informations in several ways:

  • Any declared item must be accessed according to its visibility.
  • static methods and non-static methods must be called with the proper operator (:: and -> respectively).
  • The abstract and final attributes control if and how a class can be extended.

New attributes for class items

The new visibility attributes are:

public
The item is accessible anywhere. This is the default, but it can be specified for readability.

protected
The item is accessible only from the class itself and from the classes that extend this one. For example:
/*. protected .*/ var $limited_access_var = 123;
/*. protected int .*/ function GetNo(){ ... }
private
The item is accessible only from the class where it is defined.
/*. private .*/ var $log_file = /*. resource .*/ NULL;
/*. private void .*/ function ResetStatus(){ ... }

Any non-static item declared inside a class is by default tied to an object and can be accessed through the "dynamic" dereferencing operator "->", for example $obj->item. Methods that do not use the special variable $this can be marked as static and must be accessed through the "static" dereferencing operator "::", for example ClassName::static_func(). A property cannot be static (only PHP 5 implements the static properties).

The final attribute marks methods that cannot be overridden. A private final item is allowed, although it does not make much sense, since if it is private isn't visible from outside the class.

Class constants

PHP 4 does not provide support for class constants. Constants can be declared using the define() statement at global scope.

Properties

Properties are variables automatically instantiated for every new object of the class. Every object has its own set of properties.

All the properties of the class must be declared explicitly (PHPLint restriction). At run-time you cannot assign new properties to an existing object, so that $obj->newProp = 123; is an error (PHPLint restriction).

A property can be declared using a syntax similar to this one:

/*. visibility .*/ var /*. x_type .*/
    $prop1,
    $prop2 = EXPR1,
    $prop3 = EXPR2;

Note that several properties can be declaredi in a single statement, all having the same type and visibility attributes.

The visibility attribute is optional, and the default is public.

The type is optional. It is simpler and often shorter to indicate a proper initial value.

Properties cannot be final nor static.

public and protected properties cannot be overriden nor re-defined in extended classes (PHPLint restriction).

private properties cannot be re-defined (PHPLint restriction due to the PHP 4 lack of actual support of the private visibility attribute).


IMPORTANT

The PHP interpreter initializes all the properties that lack an initial value to the NULL value. According to the type model of PHPLint, the NULL value is not allowed for variables of simple type boolean, int or float. In these cases PHPLint requires that an initial value be always specified, for example FALSE, 0 or 0.0 respectively otherwise an error is signaled.


Properties can be accessed in several ways:

$this->v
Inside a method to access a local property, or an inherited public|protected, property.

$obj->v
Everywhere to access a public property. Note that protected properties are not accessible this way, but only through $this->v. Accessing via $obj-> to protected properties is forbidden (PHPLint restriction).

Lets see how a property can be declared through some examples:

var $something;

A public property of default type mixed and undefined initial value. PHPLint raises a warning on this declaration, since the default value of this property once the object will be created is NULL, a value that might not be suitable for the intended usage of the variable.

var $counter = 123;
var $fn = "";
var $fd = /*.(resource).*/ NULL;

Three public properties of the type int, string and resource respectively. Note that the NULL value requires a formal type-cast, as we already explained.

/*. private .*/ var $names = /*. (array[int]string) .*/ array();

A private property of type array[int]string, initially empty, and that cannot be used outside its class.

Methods

Methods can have one of the visibility attributes private or protected or public. The default attribute is public.

private methods are accessible only inside the code of the class itself, and are not visible outside. private methods cannot be overridden in the child classes (PHP4 limitation).

protected methods are accessible only from the class itself and its child classes.


public methods are always accessible and can be overridden.

Methods can have the static attribute. static methods cannot use the special variable $this. static methods can be accessed only through the "::" operator. Non-static methods (the default) can be accessed only through the "->" operator.

Methods can have the final attribute. final methods cannot be overridden. private methods cannot be final.

The general syntax of methods is the same we already seen for the regular functions (see chapter Functions), apart the attributes. Lets see how a method can be declared through some examples:

function doSomething(){}

A public, non-static, method of default type undefined. PHPLint can guess the returned type from the return instruction, if any is present inside the body of the method.

/*. protected int .*/ function getCounter()
{ return $this->counter; }

A protected, non-static, method that returns an int number.

/*. public final array[int]string .*/
function getNames(/*. string .*/ $substr)
{
    $res = /*. (array[int]string) .*/ array();
    foreach($this->names as $v){
        if( strpos($v, $substr) !== FALSE ){
            $res[] = $v;
        }
    }
    return $res;
}

A public, final, method that returns an array of strings.

Methods can be accessed in several ways, depending on the context and on their attributes:

$this->f()
Inside a non-static method to access a local non-static method, or an inherited public|protected, non-static method.

parent::f()
Inside a method to access an inherited public|protected static|non-static method. Useful if the inherited method has been overridden, so parent::f() is the original method, while $this->f() (if non-static) or CLASSNAME::f() (if static) is the overriding one. Note the usage of the static resolution operator "::" also for non-static methods: in fact in this case the dynamic binding does not take place since the method we are referring to is statically determined. The typical usage is calling the parent constructor from the overriding one using parent::CLASSNAME(); (remember that if the constructor is overridden, the parent constructor isn't called automatically when a new object is created).

CLASSNAME::f()
Everywhere to access a static, public method.

$obj->f()
Everywhere to access a non-static, public method. protected methods are not accessible this way (PHPLint restriction).

PHPLint will raise an error message if a static method does use the special variable $this (PHPLint restriction).

Example

Here is a complete example of an (unuseful) class in PHP 4:


class A {

    /*. public .*/ var
        $prompt = "The current value is ",
        $counter = 0;

    /*. private .*/ var
        $internal_counter = 0,
        $list_of_names = /*.(array[int]string).*/ array();

    function A(/*. int .*/ $n)
    { 
        $this->counter = $n;
    }

    function get()
    {
        return $this->prompt . $this->counter;
    }

    /*. static string .*/
    function getParam(/*. string .*/ $name)
    {
        if( isset( $_REQUEST[$name] ) )
            return (string) $_REQUEST[$name];
        else
            return NULL;
    }
}


$title = A::getParam("TITLE");
$obj = new A(789);
echo $obj->get();  # Output: "The current value is 789"

Overriding properties

Properties cannot be overridden (PHPLint restriction).

Overriding methods

A class B is said to be a subclass of the class A if the class B extends the class A or if the class B extends a class X that is a subclass of A (note the recursive definition).

Normally, the names of the methods of a subclass differ from any other method of its parent class. However, the subclass B can override the method A::a() of its parent class defining the overriding method B::a().

The basic rule of the polymorphism in OOP is that overridden methods must be usable exactly as the original ones. For example, if A::a() is expected to return a string, the overriding method B::a() must return a string; if A::a() requires two mandatory arguments, also B::a() must be callable with two arguments. PHPLint checks accurately every overridden method: both the signature and the attributes are compared and possible incompatibilities are detected. Lets start defining what a signature is.

The signature of a method is given by

  1. the type of the returned value, possibly void if none is returned;
  2. the type of each mandatory formal argument;
  3. the type of each default formal argument;
  4. the possible presence of optional arguments /*. args .*/ (PHPLint extension).

For example, the signature of the method

/*. string .*/ function aMethod(/*. string .*/ $s, $n = 2 /*., args .*/){}

is given by its return type (string), its mandatory arguments (one of type string), its optional arguments (one of type int) and its variable number of optional arguments (args). To be concise:

string(string [, int, ...])

The attributes and the signature of the overriding method B::a() are subject to these rules (PHPLint restrictions):

  • The two methods must have the same name.
  • The two methods must be both non-static or both static.
  • The visibility of the new method must be the same or greater: if A::a() is protected, B::a() can be either protected or public; if A::a() is public, B::a() must be public.
  • final methods cannot be overridden.
  • The signature of the overriding method must be compatible with the signature of the overridden method, that is:
    • The return type must be the same of the overridden method. If the return type is an object, it may also be a sub-class.
    • For each matching formal argument, the passing method (by value, return by reference or by reference) must be the same.
    • The type of each argument must be the same of the overridden method. If the argument is an object passed by value, it may also be a sub-class.
    • If the parent method has only mandatory arguments (or no arguments at all), the overridding method can add default arguments and optional arguments.
    • If the parent method has default arguments, the overridding method can add more default arguments and optional arguments.

In this example, the subclass B overrides all the methods of its parent class A. The body of all the methods is left empty, since it does not matter in our discussion. Note that B::g() adds a default argument $y, and B::h() adds optional arguments and raises its visibility from protected to public.


class A {
    /*. void .*/ function f(){}
    /*. int  .*/ function g(/*. int .*/ $i){}
    /*. protected void .*/ function h(/*. int .*/ $x){}
}

class B extends A {
    /*. void .*/ function f(){}
    /*. int  .*/ function g(/*. int .*/ $x, /*. int .*/ $y = 0){}
    /*. public void .*/ function h(/*. int .*/ $x /*., args .*/){}
}

Special methods

A method whose name is the same as the class is assumed to be the constructor. The constructor is called implicitly by the new operator. A class constructor can be called explicitly only inside the constructor of an extended class and it cannot be called explicitly elsewhere (PHPLint restriction).

The signature of the special methods __sleep() and __wakeup() must be as follows:

/*. public array[int]string .*/ function __sleep();
/*. public void .*/ function __wakeup();

An error is raised if the method name begins with two underscore characters, since those names are reserver for future extensions of the language.

Final classes

A final class is a class that cannon be extended anymore. Since the final attribute is an extension to the PHP 4 language, it can be indicated either through PHPLint meta-code

/*. final .*/ class CLASS_NAME { ... }

The reasons why a class should be made "non-extensible" go beyond the aims of this reference manual. Take a good book about OOP if you are interested to the subject.

In the following examples we will use the PHPLint meta-code because it is shorter, although you can use a DocBlock instead with exactly the same meaning.

Abstract classes

An abstract class is a class with the abstract attribute in its declaration. The abstract attribute is an extension to the PHP 4 language, so it must be indicated either through meta-code

/*. abstract .*/ class MyAbsClass { ... }

or unsing the @abstract line tags of a DocBlock.

Abstract classes can contain abstract methods, i.e. methods whose body is left empty. Abstract methods must have the abstract attribute:

/*. abstract .*/ class MyAbsClass {

    /*. abstract void .*/ function doSomething() {}

}

An abstract class can have also non-abstracti (aka "concrete") methods and properties. The basic properties of abstract classes are:

  • Abstract classes are intended to be a model for other "concrete" classes, so that all the extended classes derived from them share a common behavior. As a logical consequence, abstract classes cannot be final.
  • An abstract class can extend another abstract class. The extended abstract class inherits the properties, the methods and the abstract methods of its parent class.
  • A concrete (i.e. non-abstract) class MUST implement all the abstract methods inherited from the abstract class it extends.
  • Your program can process abstract objects that belong to an abstract class, whatever the concrete class to which they actually belong may be.
  • You cannot instantiate an object from an abstract class.

This example should be self-explanatory. An abstract class provides the interface to a generic container of strings; every string has a name and its value can be written and read with the abstract methods set() and get():

/*. abstract .*/ class StringContainer {

    /*. abstract void .*/ function set(
        /*. string .*/ $name,
        /*. string .*/ $value){}

    /*. abstract string .*/ function get(/*. string .*/ $name){}

    /*. abstract void .*/ function dispose(){}
}

Since this class is abstract it cannot be used directly to instantiate objects, but it must be implemented in some concrete class. For example, the following example shows two concrete classes that implements StringContainer. These implementations are very crude, without error handling and with possible infinite loops: do not use them in real applications! The first implementation, StringOnFile, creates a directory whose name is randomly generated, then here it saves the value of each string in a file with its name:

class StringOnFile extends StringContainer {

    /*. private .*/ var /*. string .*/ $dir;

    /*. void .*/ function StringOnFile()
    {
        do {
            $this->dir = "strings-" . rand();
        } while( file_exists( $this->dir ) );
        mkdir( $this->dir );
    }

    /*. void .*/ function set(
        /*. string .*/ $name,
        /*. string .*/ $value)
    {
        file_put_contents( $this->dir ."/$name", $value);
    }

    /*. string .*/ function get(/*. string .*/ $name)
    {
        $s = file_get_contents( $this->dir ."/$name" );
        return ($s===FALSE)? /*. (string) .*/ NULL : $s;
    }

    /*. void .*/ function dispose()
    {
        system( "rm -r ". $this->dir );
    }
}

The second implementation, StringOnSession saves each string in the current session:

class StringOnSession extends StringContainer {

    /*. private .*/ var /*. string .*/$arr;

    /*. void .*/ function StringOnFile()
    {
        do {
            $this->arr = "strings-" . rand();
        } while( isset( $_SESSION[ $this->arr ] ) );
        $_SESSION[ $this->arr ] = array();
    }

    /*. void .*/ function set(
        /*. string .*/ $name,
        /*. string .*/ $value)
    {
        $arr = /*.(array[string]string).*/ & $_SESSION[ $this->arr ];
        $arr[$name] = $value;
    }

    /*. string .*/ function get(/*. string .*/ $name)
    {
        $arr = /*.(array[string]string).*/ & $_SESSION[ $this->arr ];
        if( ! isset( $arr[$name] ) )
            return (string) NULL;
        return $arr[$name];
    }

    /*. void .*/ function dispose()
    {
        unset( $_SESSION[ $this->arr ] );
    }
}

The power of abstract classes can be seen in the code below, where the function can handle a container without knowing anything about its concrete implementation. The object $container has only formally the type StringContainer, but actually the concrete object that will be passed to the function will be an instance of some implementation of this abstract class. By the way, this function saves every entry of an associative array into the container given:

/*. void .*/ function SaveParams(
    /*. array[string]string .*/ & $params,
    /*. StringContainer     .*/ $container)
{
    foreach($params as $k => $v)
        $container->set($k, $v);
}


$data = array("userid"=>"guest",
    "username"=>"Guest",
    "userprivileges"=>"0");

/* Save data on file: */
SaveParams($data, new StringOnFile());

/* Save data on session as well: */
SaveParams($data, new StringOnSession());


<= Definite assignment analysisPHP4 - Type conversion operators =>

Umberto Salsi

Contact
Site map
Home / Section index