PHP Allergies exercise seems to have a bug in a test

When running the tests for the Allergies exercise I’ve got 21 tests passing and 8 failing in the same place in the test itself, where the same test is run 8 times with different data. The error I’m getting is:

AllergiesTest::testAllergiesToOneAllergen with data set #0 (Allergen Object (...), 'Only allergic to cats')
Object of class Allergen could not be converted to int

/mnt/exercism-iteration/AllergiesTest.php:57
/mnt/exercism-iteration/AllergiesTest.php:56

…and the test code around that is:

    public function testAllergiesToOneAllergen($allergicTo): void
    {
        $allergies = new Allergies($allergicTo->getScore());
        
        $this->assertTrue($allergies->isAllergicTo($allergicTo));
        $otherAllergen = array_filter(Allergen::allergenList(), function ($allergen) use ($allergicTo) {
            return $allergen != $allergicTo;
        });

        array_map(function ($allergen) use ($allergies) {
            $this->assertFalse($allergies->isAllergicTo($allergen));
        }, $otherAllergen);
    }

Specifically, line 57 in the above is: return $allergen != $allergicTo; .
$allergicTo is, indeed, an instance of the Allergen class. It can convert itself to a string but I see no path to having it convert itself to an integer.

My code is:

<?php

declare(strict_types=1);

class Allergies
{
    private $allergen_list = [];
    
    private $allergens = [];
    
    public function __construct(int $score)
    {
        $this->allergen_list = [ new Allergen(Allergen::EGGS),
                                 new Allergen(Allergen::PEANUTS),
                                 new Allergen(Allergen::SHELLFISH),
                                 new Allergen(Allergen::STRAWBERRIES),
                                 new Allergen(Allergen::TOMATOES),
                                 new Allergen(Allergen::CHOCOLATE),
                                 new Allergen(Allergen::POLLEN),
                                 new Allergen(Allergen::CATS) ];
        
        $allergen_markers = array_reverse( str_split( decbin($score) ) );

        foreach ( $allergen_markers as $index => $this_allergen ) {
            if ( $this_allergen === '1' && $index < 8 ) {
                $this->allergens[] = $this->allergen_list[$index];
            }
        }
    }

    public function isAllergicTo(Allergen $allergen): bool
    {
        var_dump($allergen);
        var_dump($this->allergens);
        return in_array($allergen, $this->allergens);
    }

    public function getList(): array
    {
       return $this->allergens;
    }
}

class Allergen
{
    const EGGS = 1;
    const PEANUTS = 2;
    const SHELLFISH = 4;
    const STRAWBERRIES = 8;
    const TOMATOES = 16;
    const CHOCOLATE = 32;
    const POLLEN = 64;
    const CATS = 128;

    function __construct(public int $allergen) {}

    function __toString() { return $this->allergen; }
    
    public function getScore()
    {   
        return $this->allergen;
    }
    
    public static function allergenList(): array
    {
        return [ self::EGGS,
                 self::PEANUTS,
                 self::SHELLFISH,
                 self::STRAWBERRIES,
                 self::TOMATOES,
                 self::CHOCOLATE,
                 self::POLLEN,
                 self::CATS ];
    }
}

The test uses the array of allergens provided by the Allergy class and then compares each one ($allergen) against the provided one ($allergicTo). Each test case using the arguments from provideListOfAllergen supplies an instance of the allergen class.

So your solution is correctly failing because PHP can’t coerce $allergicTo (an instance of Allergen) to an int to be compared to your $allergen which is an int.

Ah, capisce. Thanks!

That exercise may be a little under specified. ;)

PRs/issues welcome on the php repository to propose and implement an improvement.