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

Add rule for PHP's @ operator #496

Merged
merged 8 commits into from
Apr 29, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
50 changes: 50 additions & 0 deletions src/main/php/PHPMD/Rule/CleanCode/ErrorControlOperator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php
/**
* This file is part of PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/

namespace PHPMD\Rule\CleanCode;

use PHPMD\AbstractNode;
use PHPMD\AbstractRule;
use PHPMD\Rule\ClassAware;
use PHPMD\Rule\FunctionAware;
use PHPMD\Rule\MethodAware;

/**
* Error Control Operators Rule
*
* This rule detects usage of error control operator (@).
*
* @author Kamil Szymanaski <kamil.szymanski@gmail.com>
* @link http://php.net/manual/en/language.operators.errorcontrol.php
*/
class ErrorControlOperator extends AbstractRule implements MethodAware, FunctionAware
{
/**
* Loops trough all class or function nodes and looks for '@' sign.
ravage84 marked this conversation as resolved.
Show resolved Hide resolved
*
* @param AbstractNode $node
* @return void
*/
public function apply(AbstractNode $node)
{
foreach ($node->findChildrenOfType('UnaryExpression') as $unaryExpression) {
if ($unaryExpression->getImage() === '@') {
$this->addViolation($node, array($unaryExpression->getBeginLine()));
}
}
}
}
22 changes: 22 additions & 0 deletions src/main/resources/rulesets/cleancode.xml
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,28 @@ function createArray() {
'foo' => 'bar', // not applied
"foo" => 'baz', // applied
];
}
]]>
</example>
</rule>

<rule name="ErrorControlOperator"
message="Remove error control operator '@' on line {0}."
class="PHPMD\Rule\CleanCode\ErrorControlOperator"
externalInfoUrl="http://phpmd.org/rules/cleancode.html#errorcontroloperator">
<description>
<![CDATA[
Error suppression should be avoided if possible as it doesn't just suppress the error, that
you are trying to stop, but will also suppress errors that you didn't predict would ever occur.
Consider changing error_reporting() level and/or setting up your own error handler.
]]>
</description>
<priority>1</priority>
<example>
<![CDATA[
function foo($filePath) {
ravage84 marked this conversation as resolved.
Show resolved Hide resolved
$file = @fopen($filPath); // hides exceptions
$key = @$array[$notExistingKey]; // assigns null to $key
}
]]>
</example>
Expand Down
14 changes: 14 additions & 0 deletions src/site/rst/rules/cleancode.rst
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,20 @@ Example: ::
];
}

ErrorControlOperator
====================

Since: PHPMD 2.7.0

Error suppression should be avoided if possible as it doesn't just suppress the error, that you are trying to stop, but will also suppress errors that you didn't predict would ever occur. Moreover it slows down execution of your code by average of 1.75x. Consider changing error_reporting() level and/or setting up your own error handler.

Example: ::

function foo($filePath) {
$file = @fopen($filPath); // hides exceptions
$key = @$array[$notExistingKey]; // assigns null to $key
}

Remark
======

Expand Down
2 changes: 2 additions & 0 deletions src/site/rst/rules/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,13 @@ Clean Code Rules
- `ElseExpression`__: An if expression with an else branch is basically not necessary. You can rewrite the conditions in a way that the else clause is not necessary and the code becomes simpler to read. To achieve this, use early return statements, though you may need to split the code it several smaller methods. For very simple assignments you could also use the ternary operations.
- `StaticAccess`__: Static access causes unexchangeable dependencies to other classes and leads to hard to test code. Avoid using static access at all costs and instead inject dependencies through the constructor. The only case when static access is acceptable is when used for factory methods.
- `DuplicateArrayKey`__: Defining another value for the same key in an array literal overrides the previous key/value, which makes it effectively an unused code. If it's known from the beginning that the key will have different value, there is usually no point in defining first one.
- `ErrorControlOperator`__: Error suppression should be avoided if possible as it doesn't just suppress the error, that you are trying to stop, but will also suppress errors that you didn't predict would ever occur. Moreover it slows down execution of your code by average of 1.75x. Consider changing error_reporting() level and/or setting up your own error handler.

__ cleancode.html#booleanargumentflag
__ cleancode.html#elseexpression
__ cleancode.html#staticaccess
__ cleancode.html#duplicatearraykey
__ cleancode.html#errorcontroloperator

Code Size Rules
===============
Expand Down
62 changes: 62 additions & 0 deletions src/test/php/PHPMD/Rule/CleanCode/ErrorControlOperatorTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<?php
/**
* This file is part of PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/

namespace PHPMD\Rule\CleanCode;

use PHPMD\AbstractTest;

/**
* Error Control Operator Test
*/
class ErrorControlOperatorTest extends AbstractTest
{
/**
* testAppliedToFunctions
*
* @return void
*/
public function testDoesNotApplyToOtherUnaryOperatorsInFunction()
{
$rule = new ErrorControlOperator();
$rule->setReport($this->getReportMock(1));
$rule->apply($this->getFunction());
}

/**
* testAppliedToFunctions
*
* @return void
*/
public function testAppliesToErrorControlOperatorInFunction()
{
$rule = new ErrorControlOperator();
$rule->setReport($this->getReportMock(3));
$rule->apply($this->getFunction());
}

/**
* testAppliedToClassesAndMethods
*
* @return void
*/
public function testAppliedToClassesAndMethods()
{
$rule = new ErrorControlOperator();
$rule->setReport($this->getReportMock(6));
$rule->apply($this->getClass());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php
/**
* This file is part of PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/

/**
* Class testAppliedToClassesAndMethods
*/
class testAppliedToClassesAndMethods
{
/**
* @var string
*/
private $baz = 'baz';

/**
* testAppliedToClassesAndMethods
*/
public function testAppliedToClassesAndMethods()
{
$foo = @$this->fooBar();
++$foo;
@!$baz = 1 / 0;
if (@is_readable(__FILE__)) {
$bar = new DateTime('now');
@$baz = $bar;
}
$this->baz = !$foo;
}

/**
* fooBar
*
* @return int
*/
private function fooBar()
{
@$foo = $this->baz / 0;
@$baz = !$foo;

return 2;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php
/**
* This file is part of PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/

/**
* testAppliesToErrorControlOperatorInFunction
*
* @return array
*/
function testAppliesToErrorControlOperatorInFunction()
{
$foo = @debug_backtrace();
$bar = @is_dir(__FILE__);
@$average = 3 / 0;

return [$foo, $bar, $average];
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php
/**
* This file is part of PHP Mess Detector.
*
* Copyright (c) Manuel Pichler <mapi@phpmd.org>.
* All rights reserved.
*
* Licensed under BSD License
* For full copyright and license information, please see the LICENSE file.
* Redistributions of files must retain the above copyright notice.
*
* @author Manuel Pichler <mapi@phpmd.org>
* @copyright Manuel Pichler. All rights reserved.
* @license https://opensource.org/licenses/bsd-license.php BSD License
* @link http://phpmd.org/
*/

/**
* testDoesNotApplyToOtherUnaryOperatorsInFunction
*
* @return bool
*/
function testDoesNotApplyToOtherUnaryOperatorsInFunction()
{
@$foo = is_dir(__DIR__);
$bar = !$foo;
++$bar;
$baz = ++$bar;

return !--$baz;
}