For the sake of brevity, let's say that you have two classes in your project:
namespace MyNamespace;
class Foo
{
public function myFunc(): bool
{
$i = [];
$i["1"];
return true;
}
}
namespace MyNamespace;
class Bar
{
public function myFunc(): bool
{
$i = [];
$i["1"];
return true;
}
}
Both functions myFunc will trigger w warning (no clue what would trigger a notice in PHP 8.1), but we don't want to report it for the class Foo.
Your test would then look like this:
namespace MyNamespace\Tests;
use PHPUnit\Framework\TestCase;
use MyNamespace\Foo;
use MyNamespace\Bar;
class MyTest extends TestCase
{
protected function setUp(): void
{
set_error_handler(static function (int $errorNr, string $errorStr, string $errorFile, int $errorLine, array $errorContext = []): bool {
if (str_contains('/home/awons/Projects/test/src/Foo.php', $errorFile) && $errorNr === E_WARNING) {
return true;
}
$phpUnitHandler = new \PHPUnit\Util\ErrorHandler(true, true, true, true);
return $phpUnitHandler->__invoke($errorNr, $errorStr, $errorFile, $errorLine, $errorContext);
});
}
protected function tearDown(): void
{
restore_error_handler();
}
public function testFoo(): void
{
$foo = new Foo();
self::assertTrue($foo->myFunc());
}
public function testBar(): void
{
$bar = new Bar();
self::assertTrue($bar->myFunc());
}
public function testFooAgain(): void
{
$foo = new Foo();
self::assertTrue($foo->myFunc());
}
}
This is not exactly the most performant solution and I would consider it a hack, but it should do the trick if that's what you need.
All you have to do is to make a decision about when you want to trigger the PhpUnit's error handler and when you want to ignore the notice. You can replace /home/awons/Projects/test/src/Foo.php with /vendor/ (or anything more specific to be 100% sure you got the correct path).
Also, I'm not sure how to get the current settings for the error handler. You might need to parse the config file for that or just move everything to a base class and hardcode values there (just keep them in sync with the actual settings).
::Edit::
There is even a way not to instantiate the PhpUnit's handler but just get it from the current context. All we have to do is to register an empty error handler and restore it immediately. Registering a new error handler returns the previous one.
Assuming the base class is in ./tests you can build the following abstract test case:
use PHPUnit\Framework\TestCase;
abstract class BaseTestCase extends TestCase
{
protected function setUp(): void
{
$phpUnitErrorHandler = set_error_handler(function () {
});
restore_error_handler();
set_error_handler(
static function (
int $errorNr,
string $errorStr,
string $errorFile,
int $errorLine,
array $errorContext = []
) use ($phpUnitErrorHandler): bool {
$vendorDir = realpath(__DIR__ . "/../vendor/");
if (str_contains($vendorDir, $errorFile) && $errorNr === E_NOTICE) {
return true;
}
return call_user_func_array(
$phpUnitErrorHandler,
[$errorNr, $errorStr, $errorFile, $errorLine, $errorContext]
);
}
);
}
protected function tearDown(): void
{
restore_error_handler();
}
}