php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #79482 Contravariance issue
Submitted: 2020-04-16 14:09 UTC Modified: 2020-04-16 14:17 UTC
From: john at designermonkey dot co dot uk Assigned:
Status: Not a bug Package: Unknown/Other Function
PHP Version: Irrelevant OS: n/a
Private report: No CVE-ID: None
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If you forgot your password, you can retrieve your password here.
Password:
Status:
Package:
Bug Type:
Summary:
From: john at designermonkey dot co dot uk
New email:
PHP Version: OS:

 

 [2020-04-16 14:09 UTC] john at designermonkey dot co dot uk
Description:
------------
We now have contravariance and covariance. With covariance, we can substitute a return type of `object` with a more specific type like `MyCustomClass` for example.

We cannot substitute `object` with `MyCustomClass` as a function argument typehint though.

I feel this is a bug. Why would it be allowed as a return type but not a typehint?

Test script:
---------------
<?php

class MyClass
{}


// ----------


interface TestCo
{
    public function testCo(): object;
}

class TestCoImplementation implements TestCo
{
    public function testCo(): MyClass
    {
        return new MyClass;
    }
}

$test = new TestCoImplementation;
$object = $test->testCo();
var_dump($object);


// ----------

interface TestCon
{
    public function testCon(object $object): object;
}

class TestConImplementation implements TestCon
{
    public function testCon(MyClass $object): object
    {
        return $object;
    }
}

$test = new TestCoImplementation;
$object = $test->testCo(new MyClass);
var_dump($object);


Expected result:
----------------
I would hope that the Fatal Error is not present and that the second var_dump provides my class instance.

Actual result:
--------------
/Users/john/Desktop/contract_test.php:25:
class MyClass#2 (0) {
}
PHP Fatal error:  Declaration of TestConImplementation::testCon(MyClass $object): object must be compatible with TestCon::testCon(object $object): object in /Users/john/Desktop/contract_test.php on line 37
PHP Stack trace:
PHP   1. {main}() /Users/john/Desktop/contract_test.php:0

Fatal error: Declaration of TestConImplementation::testCon(MyClass $object): object must be compatible with TestCon::testCon(object $object): object in /Users/john/Desktop/contract_test.php on line 37

Call Stack:
    0.0026     399984   1. {main}() /Users/john/Desktop/contract_test.php:0


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2020-04-16 14:15 UTC] pmmaga@php.net
-Status: Open +Status: Not a bug
 [2020-04-16 14:15 UTC] pmmaga@php.net
Thank you for taking the time to write to us, but this is not
a bug. Please double-check the documentation available at
http://www.php.net/manual/ and the instructions on how to report
a bug at http://bugs.php.net/how-to-report.php

You can read the details on the proposal: https://wiki.php.net/rfc/covariant-returns-and-contravariant-parameters The parameters are contravariant, not covariant
 [2020-04-16 14:16 UTC] derick@php.net
-Status: Not a bug +Status: Open
 [2020-04-16 14:16 UTC] derick@php.net
Thank you for taking the time to write to us, but this is not
a bug. Please double-check the documentation available at
http://www.php.net/manual/ and the instructions on how to report
a bug at http://bugs.php.net/how-to-report.php

Function arguments are contra-variant, not co-variant, meaning that an overloaded/inherited method can chose to accept a broader type. If it would allow for a more specific/narrow type, then an already existing bit of code could no longer call the overloaded with the same method arguments as the original parent class.

So this is not a bug, but an implication of the Barbara Liskov Substitution Principle.
 [2020-04-16 14:17 UTC] peehaa@php.net
-Status: Open +Status: Not a bug
 [2020-04-16 14:17 UTC] peehaa@php.net
What you are asking for would violate LSP
 [2020-04-16 16:13 UTC] tiffany@php.net
See https://3v4l.org/D1KWe

The testCon method of your TestConImplementation class needs a less specific parameter than the parent interface. As everyone else has said, your example would violate LSP.
 
PHP Copyright © 2001-2025 The PHP Group
All rights reserved.
Last updated: Fri May 09 07:01:28 2025 UTC