From 7e0e6959b083af4d6ec95f088c95789c86114974 Mon Sep 17 00:00:00 2001 From: Cameron Junge Date: Mon, 2 May 2022 10:22:29 +1200 Subject: [PATCH] Fix deprecation notice when passing `$length = null` to `Statement::bindParam()` with DBAL `2.x` (#613) Co-authored-by: Stefano Arlandini --- CHANGELOG.md | 2 + phpstan-baseline.neon | 4 +- .../Doctrine/DBAL/TracingStatementForV2.php | 2 +- .../DBAL/TracingStatementForV2Test.php | 53 +++++++++++++------ 4 files changed, 41 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 742f9e32..b9914fc0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +- Fix deprecation notice thrown when instrumenting the `PDOStatement::bindParam()` method and passing `$length = null` on DBAL `2.x` (#613) + ## 4.2.8 (2022-03-31) - Fix compatibility issue with Doctrine Bundle `>= 2.6.0` (#608) diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 0ac7d1c2..1935dfd5 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -441,12 +441,12 @@ parameters: path: tests/Tracing/Doctrine/DBAL/TracingServerInfoAwareDriverConnectionTest.php - - message: "#^Access to an undefined property PHPUnit\\\\Framework\\\\MockObject\\\\MockObject&Sentry\\\\SentryBundle\\\\Tests\\\\Tracing\\\\Doctrine\\\\DBAL\\\\TracingStatementForV2Stub\\:\\:\\$bindParamCallArgsCount\\.$#" + message: "#^Parameter \\#2 \\$decoratedStatement of class Sentry\\\\SentryBundle\\\\Tracing\\\\Doctrine\\\\DBAL\\\\TracingStatementForV2 constructor expects Doctrine\\\\DBAL\\\\Driver\\\\Statement, PHPUnit\\\\Framework\\\\MockObject\\\\MockObject&Sentry\\\\SentryBundle\\\\Tests\\\\Tracing\\\\Doctrine\\\\DBAL\\\\TracingStatementForV2Stub given\\.$#" count: 1 path: tests/Tracing/Doctrine/DBAL/TracingStatementForV2Test.php - - message: "#^Parameter \\#2 \\$decoratedStatement of class Sentry\\\\SentryBundle\\\\Tracing\\\\Doctrine\\\\DBAL\\\\TracingStatementForV2 constructor expects Doctrine\\\\DBAL\\\\Driver\\\\Statement, PHPUnit\\\\Framework\\\\MockObject\\\\MockObject&Sentry\\\\SentryBundle\\\\Tests\\\\Tracing\\\\Doctrine\\\\DBAL\\\\TracingStatementForV2Stub given\\.$#" + message: "#^Parameter \\#4 \\$length of method Sentry\\\\SentryBundle\\\\Tracing\\\\Doctrine\\\\DBAL\\\\TracingStatementForV2\\:\\:bindParam\\(\\) expects int\\|null, mixed given\\.$#" count: 1 path: tests/Tracing/Doctrine/DBAL/TracingStatementForV2Test.php diff --git a/src/Tracing/Doctrine/DBAL/TracingStatementForV2.php b/src/Tracing/Doctrine/DBAL/TracingStatementForV2.php index dfa5e64b..a12271b2 100644 --- a/src/Tracing/Doctrine/DBAL/TracingStatementForV2.php +++ b/src/Tracing/Doctrine/DBAL/TracingStatementForV2.php @@ -108,7 +108,7 @@ public function bindValue($param, $value, $type = ParameterType::STRING): bool */ public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null): bool { - return $this->decoratedStatement->bindParam($param, $variable, $type, ...\array_slice(\func_get_args(), 3)); + return $this->decoratedStatement->bindParam($param, $variable, $type, $length ?? 0, ...\array_slice(\func_get_args(), 4)); } /** diff --git a/tests/Tracing/Doctrine/DBAL/TracingStatementForV2Test.php b/tests/Tracing/Doctrine/DBAL/TracingStatementForV2Test.php index f5c5ef3c..9807001a 100644 --- a/tests/Tracing/Doctrine/DBAL/TracingStatementForV2Test.php +++ b/tests/Tracing/Doctrine/DBAL/TracingStatementForV2Test.php @@ -117,27 +117,42 @@ public function testBindValue(): void $this->assertTrue($this->statement->bindValue('foo', 'bar', ParameterType::INTEGER)); } - public function testBindParam(): void + /** + * @dataProvider bindParamDataProvider + * + * @param mixed[] $callArgs + * @param mixed[] $expectedCallArgs + */ + public function testBindParam(array $callArgs, array $expectedCallArgs): void { $variable = 'bar'; + $decoratedStatement = $this->createPartialMock(TracingStatementForV2Stub::class, array_diff(get_class_methods(TracingStatementForV2Stub::class), ['bindParam'])); - $this->decoratedStatement->expects($this->once()) - ->method('bindParam') - ->with('foo', $variable, ParameterType::INTEGER, 10) - ->willReturn(true); + $this->statement = new TracingStatementForV2($this->hub, $decoratedStatement, 'SELECT 1', ['db.system' => 'sqlite']); - $this->assertTrue($this->statement->bindParam('foo', $variable, ParameterType::INTEGER, 10)); + $this->assertTrue($this->statement->bindParam('foo', $variable, ParameterType::INTEGER, ...$callArgs)); + $this->assertSame($expectedCallArgs, $decoratedStatement->bindParamCallArgs); } - public function testBindParamForwardsLengthParamOnlyWhenExplicitlySet(): void + /** + * @return \Generator + */ + public function bindParamDataProvider(): \Generator { - $variable = 'bar'; - $decoratedStatement = $this->createPartialMock(TracingStatementForV2Stub::class, array_diff(get_class_methods(TracingStatementForV2Stub::class), ['bindParam'])); - - $this->statement = new TracingStatementForV2($this->hub, $decoratedStatement, 'SELECT 1', ['db.system' => 'sqlite']); - - $this->assertTrue($this->statement->bindParam('foo', $variable, ParameterType::INTEGER)); - $this->assertSame(3, $decoratedStatement->bindParamCallArgsCount); + yield '$length parameter not passed at all' => [ + [], + ['foo', 'bar', 1, 0], + ]; + + yield '$length parameter passed as `null`' => [ + [null], + ['foo', 'bar', 1, 0], + ]; + + yield 'additional parameters passed' => [ + [null, 'baz'], + ['foo', 'bar', 1, 0, 'baz'], + ]; } public function testErrorCode(): void @@ -211,6 +226,10 @@ public function testRowCount(): void if (!interface_exists(Statement::class)) { abstract class TracingStatementForV2Stub { + /** + * @var mixed[] + */ + public $bindParamCallArgs = []; } } else { /** @@ -219,9 +238,9 @@ abstract class TracingStatementForV2Stub abstract class TracingStatementForV2Stub implements \IteratorAggregate, Statement { /** - * @var int + * @var mixed[] */ - public $bindParamCallArgsCount = 0; + public $bindParamCallArgs = []; public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null): bool { @@ -229,7 +248,7 @@ public function bindParam($param, &$variable, $type = ParameterType::STRING, $le // parameters, regardless of whether they were originally passed // in an explicit manner, we can't use a mock to assert the number // of args used in the call to the function - $this->bindParamCallArgsCount = \func_num_args(); + $this->bindParamCallArgs = \func_get_args(); return true; }