Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhancement: Implement NoAssignByReferenceRule #914

Merged
merged 1 commit into from
Feb 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ For a full diff see [`2.7.0...main`][2.7.0...main].
### Added

- Added `allRules` parameter to allow disabling and enabling all rules ([#913]), by [@localheinz]
- Added `Expressions\NoAssignByReferenceRule`, which reports an error when a variable is assigned by reference ([#914]), by [@localheinz]

## [`2.7.0`][2.7.0]

Expand Down Expand Up @@ -617,6 +618,7 @@ For a full diff see [`362c7ea...0.1.0`][362c7ea...0.1.0].
[#911]: https://github.com/ergebnis/phpstan-rules/pull/911
[#912]: https://github.com/ergebnis/phpstan-rules/pull/912
[#913]: https://github.com/ergebnis/phpstan-rules/pull/913
[#914]: https://github.com/ergebnis/phpstan-rules/pull/914

[@cosmastech]: https://github.com/cosmastech
[@enumag]: https://github.com/enumag
Expand Down
16 changes: 16 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ This package provides the following rules for use with [`phpstan/phpstan`](https
- [`Ergebnis\PHPStan\Rules\Closures\NoParameterPassedByReferenceRule`](https://github.com/ergebnis/phpstan-rules#closuresnoparameterpassedbyreferencerule)
- [`Ergebnis\PHPStan\Rules\Closures\NoParameterWithNullableTypeDeclarationRule`](https://github.com/ergebnis/phpstan-rules#closuresnoparameterwithnullabletypedeclarationrule)
- [`Ergebnis\PHPStan\Rules\Closures\NoParameterWithNullDefaultValueRule`](https://github.com/ergebnis/phpstan-rules#closuresnoparameterwithnulldefaultvaluerule)
- [`Ergebnis\PHPStan\Rules\Expressions\NoAssignByReferenceRule`](https://github.com/ergebnis/phpstan-rules#expressionsnoassignbyreferencerule)
- [`Ergebnis\PHPStan\Rules\Expressions\NoCompactRule`](https://github.com/ergebnis/phpstan-rules#expressionsnocompactrule)
- [`Ergebnis\PHPStan\Rules\Expressions\NoErrorSuppressionRule`](https://github.com/ergebnis/phpstan-rules#expressionsnoerrorsuppressionrule)
- [`Ergebnis\PHPStan\Rules\Expressions\NoEvalRule`](https://github.com/ergebnis/phpstan-rules#expressionsnoevalrule)
Expand Down Expand Up @@ -235,6 +236,21 @@ parameters:

### Expressions

#### `Expressions\NoAssignByReferenceRule`

This rule reports an error when [a variable is assigned by reference](https://www.php.net/manual/en/language.references.whatdo.php#language.references.whatdo.assign).

##### Disabling the rule

You can set the `enabled` parameter to `false` to disable this rule.

```neon
parameters:
ergebnis:
noAssignByReference:
enabled: false
```

#### `Expressions\NoCompactRule`

This rule reports an error when the function [`compact()`](https://www.php.net/compact) is used.
Expand Down
1 change: 1 addition & 0 deletions composer-require-checker.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"null",
"PhpParser\\Comment\\Doc",
"PhpParser\\Node",
"PhpParser\\Node\\Expr\\AssignRef",
"PhpParser\\Node\\Expr\\Closure",
"PhpParser\\Node\\Expr\\ConstFetch",
"PhpParser\\Node\\Expr\\ErrorSuppress",
Expand Down
10 changes: 10 additions & 0 deletions rules.neon
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ conditionalTags:
phpstan.rules.rule: %ergebnis.noParameterPassedByReference.enabled%
Ergebnis\PHPStan\Rules\Closures\NoParameterWithNullableTypeDeclarationRule:
phpstan.rules.rule: %ergebnis.noParameterWithNullableTypeDeclaration.enabled%
Ergebnis\PHPStan\Rules\Expressions\NoAssignByReferenceRule:
phpstan.rules.rule: %ergebnis.noAssignByReference.enabled%
Ergebnis\PHPStan\Rules\Expressions\NoCompactRule:
phpstan.rules.rule: %ergebnis.noCompact.enabled%
Ergebnis\PHPStan\Rules\Expressions\NoErrorSuppressionRule:
Expand Down Expand Up @@ -63,6 +65,8 @@ parameters:
enabled: %ergebnis.allRules%
finalInAbstractClass:
enabled: %ergebnis.allRules%
noAssignByReference:
enabled: %ergebnis.allRules%
noCompact:
enabled: %ergebnis.allRules%
noConstructorParameterWithDefaultValue:
Expand Down Expand Up @@ -112,6 +116,9 @@ parametersSchema:
finalInAbstractClass: structure([
enabled: bool(),
])
noAssignByReference: structure([
enabled: bool(),
])
noCompact: structure([
enabled: bool(),
])
Expand Down Expand Up @@ -189,6 +196,9 @@ services:
-
class: Ergebnis\PHPStan\Rules\Closures\NoParameterWithNullableTypeDeclarationRule

-
class: Ergebnis\PHPStan\Rules\Expressions\NoAssignByReferenceRule

-
class: Ergebnis\PHPStan\Rules\Expressions\NoCompactRule

Expand Down
5 changes: 5 additions & 0 deletions src/ErrorIdentifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ public static function noConstructorParameterWithDefaultValue(): self
return new self('noConstructorParameterWithDefaultValue');
}

public static function noAssignByReference(): self
{
return new self('noAssignByReference');
}

public static function noErrorSuppression(): self
{
return new self('noErrorSuppression');
Expand Down
41 changes: 41 additions & 0 deletions src/Expressions/NoAssignByReferenceRule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

declare(strict_types=1);

/**
* Copyright (c) 2018-2025 Andreas Möller
*
* For the full copyright and license information, please view
* the LICENSE.md file that was distributed with this source code.
*
* @see https://github.com/ergebnis/phpstan-rules
*/

namespace Ergebnis\PHPStan\Rules\Expressions;

use Ergebnis\PHPStan\Rules\ErrorIdentifier;
use PhpParser\Node;
use PHPStan\Analyser;
use PHPStan\Rules;

/**
* @implements Rules\Rule<Node\Expr\AssignRef>
*/
final class NoAssignByReferenceRule implements Rules\Rule
{
public function getNodeType(): string
{
return Node\Expr\AssignRef::class;
}

public function processNode(
Node $node,
Analyser\Scope $scope
): array {
return [
Rules\RuleErrorBuilder::message('Assign by reference should not be used.')
->identifier(ErrorIdentifier::noAssignByReference()->toString())
->build(),
];
}
}
11 changes: 11 additions & 0 deletions test/Fixture/Expressions/NoAssignByReferenceRule/script.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

namespace Ergebnis\PHPStan\Rules\Test\Fixture\Expressions\NoAssignByReferenceRule;

$foo = 'bar';

$bar = $foo;

$baz = &$foo;
49 changes: 49 additions & 0 deletions test/Integration/Expressions/NoAssignByReferenceRuleTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

declare(strict_types=1);

/**
* Copyright (c) 2018-2025 Andreas Möller
*
* For the full copyright and license information, please view
* the LICENSE.md file that was distributed with this source code.
*
* @see https://github.com/ergebnis/phpstan-rules
*/

namespace Ergebnis\PHPStan\Rules\Test\Integration\Expressions;

use Ergebnis\PHPStan\Rules\Expressions;
use Ergebnis\PHPStan\Rules\Test;
use PHPStan\Rules;
use PHPStan\Testing;

/**
* @covers \Ergebnis\PHPStan\Rules\Expressions\NoAssignByReferenceRule
*
* @uses \Ergebnis\PHPStan\Rules\ErrorIdentifier
*
* @extends Testing\RuleTestCase<Expressions\NoAssignByReferenceRule>
*/
final class NoAssignByReferenceRuleTest extends Testing\RuleTestCase
{
use Test\Util\Helper;

public function testNoAssignByReferenceRule(): void
{
$this->analyse(
self::phpFilesIn(__DIR__ . '/../../Fixture/Expressions/NoAssignByReferenceRule'),
[
[
'Assign by reference should not be used.',
11,
],
],
);
}

protected function getRule(): Rules\Rule
{
return new Expressions\NoAssignByReferenceRule();
}
}
7 changes: 7 additions & 0 deletions test/Unit/ErrorIdentifierTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ public function testFinalReturnsErrorIdentifier(): void
self::assertSame('ergebnis.final', $errorIdentifier->toString());
}

public function testNoAssignByReferenceReturnsErrorIdentifier(): void
{
$errorIdentifier = ErrorIdentifier::noAssignByReference();

self::assertSame('ergebnis.noAssignByReference', $errorIdentifier->toString());
}

public function testNoCompactReturnsErrorIdentifier(): void
{
$errorIdentifier = ErrorIdentifier::noCompact();
Expand Down
Loading