Skip to content
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?php
/**
* PHPCompatibility, an external standard for PHP_CodeSniffer.
*
* @package PHPCompatibility
* @copyright 2012-2020 PHPCompatibility Contributors
* @license https://opensource.org/licenses/LGPL-3.0 LGPL3
* @link https://github.com/PHPCompatibility/PHPCompatibility
*/

namespace PHPCompatibility\Sniffs\ControlStructures;

use PHP_CodeSniffer\Files\File;
use PHP_CodeSniffer\Util\Tokens;
use PHPCompatibility\Sniff;

/**
* Catching exceptions without capturing them to a variable is allowed since PHP 8.0.
*
* PHP version 8.0
*
* @link https://wiki.php.net/rfc/non-capturing_catches
* @link https://www.php.net/manual/en/language.exceptions.php#language.exceptions.catch
*
* @since 10.0.0
*/
class NewNonCapturingCatchSniff extends Sniff
{

/**
* Returns an array of tokens this test wants to listen for.
*
* @since 10.0.0
*
* @return array
*/
public function register()
{
return [\T_CATCH];
}

/**
* Processes this test, when one of its tokens is encountered.
*
* @since 10.0.0
*
* @param \PHP_CodeSniffer_File $phpcsFile The file being scanned.
* @param int $stackPtr The position of the current token
* in the stack passed in $tokens.
*
* @return void
*/
public function process(File $phpcsFile, $stackPtr)
{
if ($this->supportsBelow('7.4') === false) {
return;
}

$tokens = $phpcsFile->getTokens();
$token = $tokens[$stackPtr];

// Bow out during live coding.
if (isset($token['parenthesis_opener'], $token['parenthesis_closer']) === false) {
return;
}

$lastNonEmptyToken = $phpcsFile->findPrevious(
Tokens::$emptyTokens,
($token['parenthesis_closer'] - 1),
$token['parenthesis_opener'],
true
);

if ($tokens[$lastNonEmptyToken]['code'] === \T_VARIABLE) {
return;
}

$phpcsFile->addError(
'Catching exceptions without capturing them to a variable is not supported in PHP 7.4 or earlier.',
$stackPtr,
'Found'
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php

/**
* Valid pre-PHP 8.0.
*/
try {
foo();
} catch (SomeException $ex) {
die($ex->getMessage());
} catch (ExceptionType1 | ExceptionType2 $e) {
die($e->getMessage());
} catch (CustomException::class $e) {
// ...
}

/**
* Non-capturing catch - only valid in PHP 8.0+.
*/
try {
// Some code...
} catch (ExceptionType1 | ExceptionType2) {
// Code to handle the exception.
} catch (CustomException::class) {
// ...
} catch ($exceptionObject::class) { // PHP 8 syntax - using ::class on objects.
// ...
} catch (\Exception) {
// ...
}

// Don't throw errors during live code review.
try {
// Some code...
} catch (
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
<?php
/**
* PHPCompatibility, an external standard for PHP_CodeSniffer.
*
* @package PHPCompatibility
* @copyright 2012-2020 PHPCompatibility Contributors
* @license https://opensource.org/licenses/LGPL-3.0 LGPL3
* @link https://github.com/PHPCompatibility/PHPCompatibility
*/

namespace PHPCompatibility\Tests\ControlStructures;

use PHPCompatibility\Tests\BaseSniffTest;

/**
* Test the NewNonCapturingCatch sniff.
*
* @group newNonCapturingCatch
* @group controlStructures
* @group exceptions
*
* @covers \PHPCompatibility\Sniffs\ControlStructures\NewNonCapturingCatchSniff
*
* @since 10.0.0
*/
class NewNonCapturingCatchUnitTest extends BaseSniffTest
{

/**
* testNewNonCapturingCatch
*
* @dataProvider dataNewNonCapturingCatch
*
* @param int $line The line number.
*
* @return void
*/
public function testNewNonCapturingCatch($line)
{
$file = $this->sniffFile(__FILE__, '7.4');
$this->assertError($file, $line, 'Catching exceptions without capturing them to a variable is not supported in PHP 7.4 or earlier.');
}

/**
* Data provider.
*
* @see testNewNonCapturingCatch()
*
* @return array
*/
public function dataNewNonCapturingCatch()
{
return array(
array(21),
array(23),
array(25),
array(27),
);
}


/**
* Verify no false positives are thrown for valid code.
*
* @dataProvider dataNoFalsePositives
*
* @param int $line The line number.
*
* @return void
*/
public function testNoFalsePositives($line)
{
$file = $this->sniffFile(__FILE__, '7.4');
$this->assertNoViolation($file, $line);
}

/**
* Data provider.
*
* @see testNoFalsePositives()
*
* @return array
*/
public function dataNoFalsePositives()
{
return array(
array(8),
array(10),
array(12),
array(34), // Live coding.
);
}


/**
* Verify no notices are thrown at all.
*
* @return void
*/
public function testNoViolationsInFileOnValidVersion()
{
$file = $this->sniffFile(__FILE__, '8.0');
$this->assertNoViolation($file);
}
}