rfc:remove_php4_constructors

This is an old revision of the document!


PHP RFC: Remove PHP 4 Constructors

Introduction

PHP 4 constructors are methods that have the same name as the class they are defined in. PHP 5 preserved the ability to use PHP 4 style constructors in some cases; the strangeness of when the constructor is and isn't used increases the mental model for programmers.

class Filter {
 
    // A constructor in PHP 4 and 5
    function filter($a) {}
}
// Namespaced classes do not recognize PHP 4 constructors
namespace NS;
class Filter {
 
    // Not a constructor
    function filter($a) {}
}
// Defining __construct and filter makes filter a normal method
class Filter {
    function __construct() {}
 
    // Not a constructor
    function filter($a) {}
}
 
//But defining filter first raises an E_STRICT
class Filter {
 
    // Not a constructor…
    function filter($a) {}
 
    // This raises E_STRICT
    function __construct() {}
}

Proposal

PHP 7 will emit E_DEPRECATED whenever a PHP 4 constructor is defined. When the method name matches the class name, the class is not in a namespace, and a PHP 5 constructor (__construct) is not present then an E_DEPRECATED will be emitted. PHP 8 will stop emitting E_DEPRECATED and the methods will not be recognized as constructors.

PHP 7 will also stop emitting E_STRICT when a method with the same name as the class is present as well as __construct.

Some code samples in the Examples section show how code is impacted.

Backward Incompatible Changes

Since an E_DEPRECATED will be emitted in PHP 7 there may be some backwards compatibility breaks when people use custom error handlers.

In PHP 8 recognition for old constructors will be outright removed, meaning that anything without a __construct will not work. The fix is to rename the constructor to __construct.

Examples

class Filter {
 
    // PHP 5: filter is a constructor
    // PHP 7: filter is a constructor and E_DEPRECATED is raised
    // PHP 8: filter is a normal method and is not a constructor; no E_DEPRECATED is raised
    function filter($a) {}
}
 
$filter = new ReflectionMethod('Filter', 'filter');
 
// PHP 5: bool(true)
// PHP 7: bool(true)
// PHP 8: bool(false)
var_dump($filter->isConstructor());
// function filter is not used as constructor in PHP 5+
class Filter {
    // PHP 5: E_STRICT "Redefining already defined constructor"
    // PHP 7: No error is raised
    // PHP 8: No error is raised
    function filter($a) {}
    function __construct() {}
}
// function filter is not used as constructor in PHP 5+
class Filter {
    function __construct() {}
 
    // PHP 5.0.0 - 5.2.13, 5.3.0 - 5.3.2: E_STRICT "Redefining already defined constructor"
    // PHP 5.2.14 - 5.2.17, 5.3.3 - 5.6: No error is raised
    // PHP 7: No error is raised
    // PHP 8: No error is raised
    function filter($a) {}
}
class Filter { 
    function filter() {}
}
 
class FilterX extends Filter {
 
    function __construct() {
        // PHP 5: Filter::filter is called; no error
        // PHP 7: Filter::filter is called; no error
        // PHP 8: "Fatal error: Cannot call constructor"
        parent::__construct();
    }
 
}
 
new FilterX();

Voting

This RFC targets PHP 7 and PHP 8. Please read the RFC to understand what is being proposed.

This RFC requires 2/3 vote in favor of deprecating and removing PHP 4 style constructors to pass.

Patches and Tests

An implementation based on the master branch can be found here: https://github.com/php/php-src/pull/1061

rfc/remove_php4_constructors.1424207048.txt.gz · Last modified: 2017/09/22 13:28 (external edit)