vscode-intelephense icon indicating copy to clipboard operation
vscode-intelephense copied to clipboard

Undefined method in class that implemented interface

Open Rzhevsky87 opened this issue 3 years ago • 5 comments

Describe the bug I have class "Calculator" that have dependency injection against interface "FigureInterface". I create new object this class "Calculator" with object class that implement this interface - "Square". In method "Calculator" i use method from "Square" and intelephense report me problem: "Undefined method 'getParams'.". But php is correctly execute. This is typical error for Laravel use.

To Reproduce

<?php

interface FigureInterface
{
   
}

class Square implements FigureInterface
{
    protected float $sideLength;

    public function __construct($sideLength = 1.0)
    {
        $this->sideLength = $sideLength ?: 1.0;
    }

    public function getParams()
    {
        return $this->sideLength;
    }
}

class Calculator
{
    protected FigureInterface $figure;

    public function __construct(FigureInterface $figure)
    {
        $this->figure = $figure;
    }
    
    public function getAreaSquare(): float
    {
        $sideLength = $this->figure->getParams();
        $s = $sideLength * $sideLength;
        return floatval($s);
    }
}

$square = new Square(2.0);
$calculator = new Calculator($square);

echo $calculator->getAreaSquare();

?>

Expected behavior I expect that the intelephense will not return an error and will allow to jump to the place where the method is implemented. Because php is correctly.

Screenshots err

Platform and version OS and Intelephense version Ubuntu 18.04 PHP Intelephense v1.7.1

Rzhevsky87 avatar Oct 20 '21 14:10 Rzhevsky87

In your example FigureInterface is empty. The purpose of an interface is to enforce a contract. In your example it appears you want to enforce the implementation of a getParams method. The answer would be to declare getParams in FigureInterface.

bmewburn avatar Oct 21 '21 04:10 bmewburn

@bmewburn My example is just a theoretical code example. I can declare many methods in FigureInterface, and one method that is not declared in the interface but is present in the class will return an error. And the documentation doesn't say that a class that implements an interface should only have methods declared in the interface. This is problem.

Rzhevsky87 avatar Oct 22 '21 07:10 Rzhevsky87

I understand it's just a example but to continue with it, your code only works with a specific implementation of FigureInterface, that is Square. This is ok at runtime because it just so happens to be a Square. This is information only available at runtime or is internal knowledge that you have on how the code works. You know that you will never pass Triangle to it and have it break. It's the same with laravel interfaces. There's some concrete class that has extra methods that is the default class that everyone uses and some documentation and a promise that at runtime it's all ok.

Other languages that have a compile time type check (which is what intelephense is trying to do) would force the dev to cast the FigureInterface to Square here (<Square>$this->figure)->getParams(). PHP doesn't have such constructs. So there lies the problem. Should intelephense be safe or loose here with warnings? Currently it's being safe.

bmewburn avatar Oct 29 '21 04:10 bmewburn

Perhaps the ability to just turn the warning off, A comment on or around the offending line, useful if the error is handlet in runtime

class Controller {
...
//@CHECK OFF init may be defined in the extending class
        if(method_exists($this,'init'))
            $this->init();   <-- intelephpense gives error init undefined
//@CHECK ON
}
..
class ProductController extends Controller {
... 
public function init() {
...

leifnel avatar Jan 15 '22 11:01 leifnel

This is still not working.

axelf avatar Jun 30 '22 22:06 axelf