Skip to content

Commit

Permalink
Merge pull request #165 from jrfnl/feature/required-optional-function…
Browse files Browse the repository at this point in the history
…-parameters

Add requiredOptionalFunctionParameters sniff.
  • Loading branch information
wimg committed Aug 13, 2016
2 parents c511a43 + 99ffb37 commit db2e39c
Show file tree
Hide file tree
Showing 3 changed files with 228 additions and 0 deletions.
126 changes: 126 additions & 0 deletions Sniffs/PHP/RequiredOptionalFunctionParametersSniff.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<?php
/**
* PHPCompatibility_Sniffs_PHP_RequiredOptionalFunctionParametersSniff.
*
* @category PHP
* @package PHPCompatibility
* @author Wim Godden <wim.godden@cu.be>
*/

/**
* PHPCompatibility_Sniffs_PHP_RequiredOptionalFunctionParametersSniff.
*
* @category PHP
* @package PHPCompatibility
* @author Wim Godden <wim.godden@cu.be>
*/
class PHPCompatibility_Sniffs_PHP_RequiredOptionalFunctionParametersSniff extends PHPCompatibility_Sniff
{

/**
* A list of function parameters, which were required in older versions and became optional later on.
*
* The array lists : version number with true (required) and false (optional).
*
* The index is the location of the parameter in the parameter list, starting at 0 !
* If's sufficient to list the last version in which the parameter was still required.
*
* @var array
*/
protected $functionParameters = array(
'preg_match_all' => array(
2 => array(
'name' => 'matches',
'5.3' => true,
'5.4' => false,
),
),
'stream_socket_enable_crypto' => array(
2 => array(
'name' => 'crypto_type',
'5.5' => true,
'5.6' => false,
),
),
);


/**
* Returns an array of tokens this test wants to listen for.
*
* @return array
*/
public function register()
{
return array(T_STRING);
}//end register()

/**
* Processes this test, when one of its tokens is encountered.
*
* @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(PHP_CodeSniffer_File $phpcsFile, $stackPtr)
{
$tokens = $phpcsFile->getTokens();

$ignore = array(
T_DOUBLE_COLON,
T_OBJECT_OPERATOR,
T_FUNCTION,
T_CONST,
);

$prevToken = $phpcsFile->findPrevious(T_WHITESPACE, ($stackPtr - 1), null, true);
if (in_array($tokens[$prevToken]['code'], $ignore) === true) {
// Not a call to a PHP function.
return;
}

$function = strtolower($tokens[$stackPtr]['content']);

if (isset($this->functionParameters[$function]) === false) {
return;
}

$parameterCount = $this->getFunctionCallParameterCount($phpcsFile, $stackPtr);
if ($parameterCount === 0) {
return;
}

// If the parameter count returned > 0, we know there will be valid open parenthesis.
$openParenthesis = $phpcsFile->findNext(PHP_CodeSniffer_Tokens::$emptyTokens, $stackPtr + 1, null, true, null, true);
$parameterOffsetFound = $parameterCount - 1;
$requiredVersion = null;
$parameterName = null;

foreach($this->functionParameters[$function] as $offset => $parameterDetails) {
if ($offset > $parameterOffsetFound) {
foreach ($parameterDetails as $version => $present) {
if ($version !== 'name' && $present === true && $this->supportsBelow($version)) {
$requiredVersion = $version;
$parameterName = $parameterDetails['name'];
}
}
}
}

if (isset($requiredVersion, $parameterName)) {

$error = 'The "%s" parameter for function %s is missing, but was required for PHP version %s and lower';
$errorCode = 'MissingRequiredParameter';
$data = array(
$parameterName,
$function,
$requiredVersion,
);
$phpcsFile->addError($error, $openParenthesis, $errorCode, $data);
}

}//end process()

}//end class
93 changes: 93 additions & 0 deletions Tests/Sniffs/PHP/RequiredOptionalFunctionParameterSniffTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
<?php
/**
* Required Optional Functions Parameter Sniff test file
*
* @package PHPCompatibility
*/


/**
* Required Optional Parameter Sniff test file
*
* @uses BaseSniffTest
* @package PHPCompatibility
* @author Wim Godden <wim@cu.be>
*/
class RequiredOptionalFunctionParameterSniffTest extends BaseSniffTest
{

const TEST_FILE = 'sniff-examples/required_optional_function_parameters.php';

/**
* testRequiredOptionalParameter
*
* @dataProvider dataRequiredOptionalParameter
*
* @param string $functionName Function name.
* @param string $parameterName Parameter name.
* @param string $requiredUpTo The last PHP version in which the parameter was still required.
* @param array $lines The line numbers in the test file which apply to this class.
* @param string $okVersion A PHP version in which to test for no violation.
*
* @return void
*/
public function testRequiredOptionalParameter($functionName, $parameterName, $requiredUpTo, $lines, $okVersion)
{
$file = $this->sniffFile(self::TEST_FILE, $requiredUpTo);
foreach ($lines as $line) {
$this->assertError($file, $line, "The \"{$parameterName}\" parameter for function {$functionName} is missing, but was required for PHP version {$requiredUpTo} and lower");
}

$file = $this->sniffFile(self::TEST_FILE, $okVersion);
foreach ($lines as $line) {
$this->assertNoViolation($file, $line);
}
}

/**
* Data provider.
*
* @see testRequiredOptionalParameter()
*
* @return array
*/
public function dataRequiredOptionalParameter()
{
return array(
array('preg_match_all', 'matches', '5.3', array(8), '5.4'),
array('stream_socket_enable_crypto', 'crypto_type', '5.5', array(9), '5.6'),
);
}


/**
* testValidParameter
*
* @dataProvider dataValidParameter
*
* @param int $line The line number.
*
* @return void
*/
public function testValidParameter($line)
{
$file = $this->sniffFile(self::TEST_FILE, '7.0');
$this->assertNoViolation($file, $line);
}

/**
* Data provider.
*
* @see testValidParameter()
*
* @return array
*/
public function dataValidParameter()
{
return array(
array(4),
array(5),
);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

// These are ok.
preg_match_all('`[a-z]+`', $subject, $matches);
stream_socket_enable_crypto($fp, true, STREAM_CRYPTO_METHOD_SSLv23_CLIENT);

// These are not.
preg_match_all('`[a-z]+`', $subject);
stream_socket_enable_crypto($fp, true);

0 comments on commit db2e39c

Please sign in to comment.