Skip to the content
Documentation
Help Start
Reading in:
  • German: 9,090 of 9,090 pages
About the help in other languages
All help pages

Old-style constructors and static calls

PHP 8 no longer runs a method named after its class as the constructor, and stops on instance methods called statically. How to find both in an old extension and fix them without breaking code that calls the old names.

Download as PDF

Address: https://doc.exponential.earth/exphelp/viewer/help/extension-development/part-4-upgrading/old-constructors-and-static-calls.md

On this page

Old-style constructors and static calls

Part 4, chapter 7. PHP 4 had no __construct(): the constructor was the method with the class's name. PHP 5 and 7 still accepted that, and PHP 8 does not. Many extensions written in the 2000s use the old form, and almost every one of their template operators does, because the kernel's own examples did. This chapter shows how the failure looks, how to find every case, and the fix this project uses. The second half covers its sibling, the static call to an instance method.

Why it is dangerous

A missing constructor does not stop anything when the object is built. PHP 8 simply does not call the method, so the object exists, but its properties were never set. The error comes later, somewhere else, and points at the wrong place.

A template operator is the classic case. This is the operator class of the str_replace extension (se7enxweb/str_replace), as it is in October 2026:

class MyStrReplaceOperator
{
    /*!
     Constructor
    */
    function MyStrReplaceOperator()
    {
        $this->Operators = array( 'ezstr_replace');
    }

    function operatorList()
    {
        return $this->Operators;
    }
    // ...
}

On PHP 8, new MyStrReplaceOperator() leaves $this->Operators unset, operatorList() returns null, and the template engine reports "Object problem with operator" on the first template that uses the operator. Nothing in that message mentions a constructor.

In se7enxweb/ezfind, commit 7ff9824 fixed five classes with the same problem. Its message lists the symptoms, which show how far from the cause they can appear:

ClassWhat went wrong on PHP 8
eZFindResultNodereading a search result node ended in an error
eZFindResultObjectthe parent constructor ran with the wrong data
ezfSearchResultInfofacets, errors and the response header of a search were empty
ezfUpdateSearchIndexSolrindexing from the command line stopped at once
ezfModuleFunctionCollectionan empty constructor, made a real one

Find every case

A method is an old-style constructor when its name equals its class's name, case-insensitively, in a class without __construct(). This loop prints every class that has a method of its own name:

cd extension/myoldext
grep -rhoE '^\s*(abstract\s+|final\s+)?class\s+[A-Za-z0-9_]+' --include='*.php' . | awk '{print $NF}' | sort -u | while read c; do
  grep -rliE "function\s+&?\s*$c\s*\(" --include='*.php' . | sed "s|^|$c: |"
done

Check each file it prints. PHPCompatibility for PHP_CodeSniffer reports the same thing, if you already use it (Tests and CI for an upgraded extension).

The fix

Rename the method to __construct(), and keep the old name as a method that calls it, for code that calls the old name directly. That is what se7enxweb/ezfind, commit 7ff9824, did:

// before
function ezfSearchResultInfo( array $resultArray )
{
    $this->ResultArray = $resultArray;
}

// after
function __construct( array $resultArray )
{
    $this->ResultArray = $resultArray;
}

/**
 * The constructor under its old name, which PHP 8 no longer calls on "new"; kept for code that calls it.
 *
 * @deprecated Use the constructor
 */
function ezfSearchResultInfo( array $resultArray )
{
    $this->__construct( $resultArray );
}

Why keep the old name? Child classes, and other extensions, may call parent::ezfSearchResultInfo( ... ) or $this->ezfSearchResultInfo( ... ). Without the wrapper, those become fatal errors.

For the template operator above, the whole fix is:

<?php
class MyStrReplaceOperator
{
    public $Operators;

    function __construct()
    {
        $this->Operators = array( 'ezstr_replace' );
    }

    /**
     * @deprecated Use the constructor
     */
    function MyStrReplaceOperator()
    {
        $this->__construct();
    }

    function operatorList()
    {
        return $this->Operators;
    }
}

Note the declared property public $Operators;: without it, PHP 8.2 reports a dynamic property (Dynamic properties).

Classes with a parent

Look at what the old constructor did with its parent. There are three cases:

The old constructorWhat the new one does
called $this->ParentClass( ... ) or parent::ParentClass( ... )calls parent::__construct( ... ) with the same arguments
did not call the parent at alldoes not call it either (in ezfind, eZFindResultObject keeps it that way on purpose)
did not exist; only the parent had onenothing to do, the parent's __construct() runs

If the parent is a kernel class, its constructor is already __construct() in Exponential 6. For example, eZPersistentObject subclasses call parent::__construct( $row ).

Static calls to instance methods

PHP 5 let you call an instance method as ClassName::method(), with a notice, as long as it did not touch $this. PHP 8 throws an Error:

Uncaught Error: Non-static method eZSelectionType::classAttributeContent() cannot be called statically

From se7enxweb/sevenx_themes_media, commit f7d93c0:

// before
$classContent = eZSelectionType::classAttributeContent( $classAttr );

// after
$classContent = $classAttr->attribute( 'content' );

There are three ways to fix such a call, in this order of preference:

  1. Use the higher-level API. As above: the class attribute knows its datatype and returns its content.
  2. Get an instance. Many kernel classes have one: eZINI::instance(), eZDB::instance(), eZHTTPTool::instance(), eZLocale::instance(), eZTemplate::factory(), or a fetch: eZContentObject::fetch( $id ), eZContentObjectTreeNode::fetch( $nodeID ).
  3. Make your own method static, but only your own, and only if it does not use $this.

To find candidates, list the static-looking calls to kernel classes and check each method's declaration:

grep -rnoE '\beZ[A-Za-z]+::[a-zA-Z_]+\s*\(' --include='*.php' extension/myoldext/ | sort -u
grep -n "function classAttributeContent" kernel/classes/datatypes/ezselection/ezselectiontype.php

A declaration without static means the call needs an instance.

The reverse: $this in a static method

Old code sometimes declares a method static and still uses $this inside, which worked when the method happened to be called on an object. PHP 8 stops with "Using $this when not in object context". Remove static, or replace $this-> with self:: or static:: if the method really is static.

Checklist

  • To do: Every class with a method of its own name has a __construct().
  • To do: The old name stays as a deprecated wrapper.
  • To do: Each new constructor calls the parent exactly when the old one did.
  • To do: Every property set in a constructor is declared.
  • To do: No ClassName::method() call to a method declared without static.

Become an Exponential Partner

Partners share their information, provide funding, contribute back and develop the products with us, and that is how Exponential grows. A partner website and dashboard are planned for mid-2027: please become a partner today to speed up our growth rate and land new features faster.

Something wrong on this page? Report an error

Documentation license

This documentation is free documentation, licensed under the GNU Free Documentation License 1.3 or later.

Exponential Copyright © 1998-2026 Exponential Foundation and 7x