Unsafe usage of `new static()`PHP-W1014
This issue is raised for new static()
calls that might break once the class is extended and the constructor is overridden with different type parameters.
Extending classes with calls to new static()
is error-prone and will likely break your application. Restructure your code to prevent such usage.
Bad practice
class Controller
{
public function __construct(string $name)
{
}
public function getController()
{
return new static('Base');
}
}
class UserController extends Controller
{
// constructor method is overridden
public function __construct(int $i)
{
}
}
// valid: will return an instance of "Controller" class
(new Controller('Base'))->getController();
// invalid: will return a Fatal Error: "Argument #1 ($i) must be of type int, string given"
(new UserController(1))->getController();
Recommended
Make the class final
This is the easiest course of action - if the class does not need to be extended, but is open for inheritance anyway, (perhaps by accident) just make it final. At that point, you can also change new static()
to just new self()
without breaking functionality.
final class Controller
{
public function __construct(string $name)
{
}
public function getController()
{
return new static('Base');
}
}
Make the constructor final
If you want the class open for extension, you can disallow overriding the constructor in child classes and make the code safe that way.
final class Controller
{
final public function __construct(string $name)
{
}
public function getController()
{
return new static('Base');
}
}
Make the constructor abstract
Signatures of abstract constructors are enforced in child classes. The disadvantage of this approach is that the child class must define its own constructor, it cannot inherit the parent one.
class Controller
{
abstract public function __construct(string $name);
public function getController()
{
return new static('Base');
}
}
Enforce constructor signature through an interface
Making the constructor abstract can also be achieved by an interface while keeping the implementation in the parent class. The child class doesn’t have to define its own constructor. It'll inherit the parent one, but PHP will enforce the constructor's signature if the child class defines one.
interface ControllerInterface
{
public function __construct(string $name);
}
class Controller implements ControllerInterface
{
public function __construct(string $name)
{
}
public function getController()
{
return new static('Base');
}
}