Type hinting ClassName in php
Asked Answered
C

2

5

I would like to type hint class name in method parameter, in this code:

    public function addScore($scoreClassName): self
    {
        $this->score = new $scoreClassName($this->score);
        return $this;
    }

$scoreClassName should be class name of a class which implements certain Interface. Something like:

    public function addScore(CalculatesScore::class $scoreClassName): self
    {
        $this->score = new $scoreClassName($this->score);
        return $this;
    }

Is there any way to do it? If not, could you suggest a workaround?

EDIT: Best solution i found so far to my question

    public function addScore(string $scoreClassName): self
    {
        $implementedInterfaces = class_implements($scoreClassName);
        if (!in_array(CalculatesScore::class, $implementedInterfaces)) 
        {
            throw new \TypeError($this->getTypeErrorMessage($scoreClassName));
        }
        $this->score = new $scoreClassName($this->score);

        return $this;
    }
Crotty answered 4/12, 2019 at 9:48 Comment(2)
No, you can only type hint on an actual class, or generic types like string. I'm not sure if string $scoreClassName = CalculateScore::class would work. You'd then have to test in the method itself that the class is appropriate.Civility
In PHP fully qualified class names are strings so string $scoreClassName should work but you can't put restrictions on this. PHP does not have generics which allow for constraints like e.g. C# doesAcnode
C
3

You can't type-hint on a specific string. You can, however, set a default string value.

To ensure you've instantiated a class of the correct type you'd have to do a check in the method body itself.

public function addScore(string $scoreClassName = CalculatesScore::class): self
{
    $score = new $scoreClassName($this->score);
    if (!$score instanceof CalculatesScore) 
    {
        throw new InvalidArgumentException("Invalid class score type: $scoreClassName");
    }
    $this->score = $score;
    return $this;
}

I'd argue that this isn't really the right way to do it, you should probably be using dependency injection instead, and instantiate the score class prior to passing it to this class. It makes the dependency more explicit and simpler to control. The actual code is also a lot simpler.

public function addScore(CalculatesScore $scoreClass): self
{
    $this->score = $scoreClass;
    return $this;
}
Civility answered 4/12, 2019 at 9:54 Comment(1)
Well, i need to pass $this->score as an argument to constructor and looking for cleaner way than php $newScore = NewScore($scoreCalculator->getScore()); $scoreCalculator->addScore($newScore); Shiprigged
P
3

If you want to type hint a class string solely for the purpose of passing that information to the IDE (to get usage search and autocomplete to work), and your IDE uses Psalm, you can use the class-string type hint in a docblock comment. So for your code it would look like this:

/**
 * @param class-string<CalculatesScore> $scoreClassName
 * @return $this
 */
public function addScore($scoreClassName): self
{
    $this->score = new $scoreClassName($this->score);
    return $this;
}
Praline answered 18/12, 2023 at 6:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.