2019-10-13 05:59:52 +00:00
< ? php
2021-05-09 20:15:43 +00:00
declare ( strict_types = 1 );
2019-09-22 18:57:03 +00:00
namespace Rector\Php70\Rector\FuncCall ;
2018-10-08 05:19:10 +00:00
use PhpParser\Node ;
use PhpParser\Node\Arg ;
use PhpParser\Node\Expr\ArrayDimFetch ;
use PhpParser\Node\Expr\Assign ;
use PhpParser\Node\Expr\BinaryOp\Concat ;
use PhpParser\Node\Expr\FuncCall ;
use PhpParser\Node\Expr\Ternary ;
use PhpParser\Node\Expr\Variable ;
use PhpParser\Node\Name ;
use PhpParser\Node\Scalar\LNumber ;
use PhpParser\Node\Scalar\String_ ;
2020-02-06 21:48:18 +00:00
use Rector\Core\Rector\AbstractRector ;
2021-09-24 14:11:08 +00:00
use Rector\Core\ValueObject\PhpVersionFeature ;
2019-04-13 09:20:27 +00:00
use Rector\NodeTypeResolver\Node\AttributeKey ;
2019-09-23 14:36:58 +00:00
use Rector\Php70\EregToPcreTransformer ;
2021-09-24 14:11:08 +00:00
use Rector\VersionBonding\Contract\MinPhpVersionInterface ;
2020-11-16 17:50:38 +00:00
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample ;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition ;
2018-10-08 05:19:10 +00:00
/**
2021-04-10 18:47:17 +00:00
* @ changelog http :// php . net / reference . pcre . pattern . posix https :// stackoverflow . com / a / 17033826 / 1348344 https :// docstore . mik . ua / orelly / webprog / pcook / ch13_02 . htm
2020-02-23 17:51:22 +00:00
*
2021-03-12 22:20:25 +00:00
* @ see \Rector\Tests\Php70\Rector\FuncCall\EregToPregMatchRector\EregToPregMatchRectorTest
2018-10-08 05:19:10 +00:00
*/
2021-09-24 14:11:08 +00:00
final class EregToPregMatchRector extends \Rector\Core\Rector\AbstractRector implements \Rector\VersionBonding\Contract\MinPhpVersionInterface
2018-10-08 05:19:10 +00:00
{
/**
2021-02-23 01:25:34 +00:00
* @ var array < string , string >
2018-10-08 05:19:10 +00:00
*/
2021-05-09 20:15:43 +00:00
private const OLD_NAMES_TO_NEW_ONES = [ 'ereg' => 'preg_match' , 'eregi' => 'preg_match' , 'ereg_replace' => 'preg_replace' , 'eregi_replace' => 'preg_replace' , 'split' => 'preg_split' , 'spliti' => 'preg_split' ];
2018-10-08 05:19:10 +00:00
/**
2021-05-10 23:39:21 +00:00
* @ var \Rector\Php70\EregToPcreTransformer
2018-10-08 05:19:10 +00:00
*/
private $eregToPcreTransformer ;
2021-05-10 22:23:08 +00:00
public function __construct ( \Rector\Php70\EregToPcreTransformer $eregToPcreTransformer )
2018-10-08 05:19:10 +00:00
{
$this -> eregToPcreTransformer = $eregToPcreTransformer ;
}
2021-09-24 14:11:08 +00:00
public function provideMinPhpVersion () : int
{
return \Rector\Core\ValueObject\PhpVersionFeature :: NO_EREG_FUNCTION ;
}
2021-05-10 22:23:08 +00:00
public function getRuleDefinition () : \Symplify\RuleDocGenerator\ValueObject\RuleDefinition
2018-10-08 05:19:10 +00:00
{
2021-05-10 22:23:08 +00:00
return new \Symplify\RuleDocGenerator\ValueObject\RuleDefinition ( 'Changes ereg*() to preg*() calls' , [ new \Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample ( 'ereg("hi")' , 'preg_match("#hi#");' )]);
2018-10-08 05:19:10 +00:00
}
/**
2021-02-27 00:06:15 +00:00
* @ return array < class - string < Node >>
2018-10-08 05:19:10 +00:00
*/
2021-05-09 20:15:43 +00:00
public function getNodeTypes () : array
2018-10-08 05:19:10 +00:00
{
2021-05-10 22:23:08 +00:00
return [ \PhpParser\Node\Expr\FuncCall :: class ];
2018-10-08 05:19:10 +00:00
}
/**
2021-07-05 22:50:18 +00:00
* @ param FuncCall $node
2018-10-08 05:19:10 +00:00
*/
2021-07-05 22:50:18 +00:00
public function refactor ( \PhpParser\Node $node ) : ? \PhpParser\Node
2018-10-08 05:19:10 +00:00
{
2018-10-15 04:36:58 +00:00
$functionName = $this -> getName ( $node );
2019-01-14 18:21:23 +00:00
if ( $functionName === null ) {
return null ;
}
2021-05-09 20:15:43 +00:00
if ( ! isset ( self :: OLD_NAMES_TO_NEW_ONES [ $functionName ])) {
2018-10-21 10:19:14 +00:00
return null ;
2018-10-08 05:19:10 +00:00
}
2018-10-15 04:36:58 +00:00
$patternNode = $node -> args [ 0 ] -> value ;
2021-05-10 22:23:08 +00:00
if ( $patternNode instanceof \PhpParser\Node\Scalar\String_ ) {
2018-10-15 04:36:58 +00:00
$this -> processStringPattern ( $node , $patternNode , $functionName );
2021-05-10 22:23:08 +00:00
} elseif ( $patternNode instanceof \PhpParser\Node\Expr\Variable ) {
2018-10-15 04:36:58 +00:00
$this -> processVariablePattern ( $node , $patternNode , $functionName );
2018-10-08 05:19:10 +00:00
}
2018-10-15 04:36:58 +00:00
$this -> processSplitLimitArgument ( $node , $functionName );
2021-05-10 22:23:08 +00:00
$node -> name = new \PhpParser\Node\Name ( self :: OLD_NAMES_TO_NEW_ONES [ $functionName ]);
2018-10-08 05:19:10 +00:00
// ereg|eregi 3rd argument return value fix
2021-05-09 20:15:43 +00:00
if ( \in_array ( $functionName , [ 'ereg' , 'eregi' ], \true ) && isset ( $node -> args [ 2 ])) {
2021-05-10 22:23:08 +00:00
$parentNode = $node -> getAttribute ( \Rector\NodeTypeResolver\Node\AttributeKey :: PARENT_NODE );
if ( $parentNode instanceof \PhpParser\Node\Expr\Assign ) {
2018-10-15 04:36:58 +00:00
return $this -> createTernaryWithStrlenOfFirstMatch ( $node );
2018-10-08 05:19:10 +00:00
}
}
2018-10-15 04:36:58 +00:00
return $node ;
2018-10-08 05:19:10 +00:00
}
2021-05-10 22:23:08 +00:00
private function processStringPattern ( \PhpParser\Node\Expr\FuncCall $funcCall , \PhpParser\Node\Scalar\String_ $string , string $functionName ) : void
2018-10-08 05:19:10 +00:00
{
2020-06-29 21:19:37 +00:00
$pattern = $string -> value ;
2018-10-08 05:19:10 +00:00
$pattern = $this -> eregToPcreTransformer -> transform ( $pattern , $this -> isCaseInsensitiveFunction ( $functionName ));
2021-05-10 22:23:08 +00:00
$funcCall -> args [ 0 ] -> value = new \PhpParser\Node\Scalar\String_ ( $pattern );
2018-10-08 05:19:10 +00:00
}
2021-05-10 22:23:08 +00:00
private function processVariablePattern ( \PhpParser\Node\Expr\FuncCall $funcCall , \PhpParser\Node\Expr\Variable $variable , string $functionName ) : void
2018-10-08 05:19:10 +00:00
{
2021-05-10 22:23:08 +00:00
$pregQuotePatternNode = $this -> nodeFactory -> createFuncCall ( 'preg_quote' , [ new \PhpParser\Node\Arg ( $variable ), new \PhpParser\Node\Arg ( new \PhpParser\Node\Scalar\String_ ( '#' ))]);
$startConcat = new \PhpParser\Node\Expr\BinaryOp\Concat ( new \PhpParser\Node\Scalar\String_ ( '#' ), $pregQuotePatternNode );
2018-10-08 05:19:10 +00:00
$endDelimiter = $this -> isCaseInsensitiveFunction ( $functionName ) ? '#mi' : '#m' ;
2021-05-10 22:23:08 +00:00
$concat = new \PhpParser\Node\Expr\BinaryOp\Concat ( $startConcat , new \PhpParser\Node\Scalar\String_ ( $endDelimiter ));
2019-02-22 17:25:31 +00:00
$funcCall -> args [ 0 ] -> value = $concat ;
2018-10-08 05:19:10 +00:00
}
/**
* Equivalent of :
* split ( ' ' , 'hey Tom' , 0 );
* ↓
* preg_split ( '# #' , 'hey Tom' , 1 );
*/
2021-05-10 22:23:08 +00:00
private function processSplitLimitArgument ( \PhpParser\Node\Expr\FuncCall $funcCall , string $functionName ) : void
2018-10-08 05:19:10 +00:00
{
2021-05-30 10:12:56 +00:00
if ( \strncmp ( $functionName , 'split' , \strlen ( 'split' )) !== 0 ) {
2018-10-08 05:19:10 +00:00
return ;
}
// 3rd argument - $limit, 0 → 1
2021-05-09 20:15:43 +00:00
if ( ! isset ( $funcCall -> args [ 2 ])) {
2018-10-08 05:19:10 +00:00
return ;
}
2021-05-10 22:23:08 +00:00
if ( ! $funcCall -> args [ 2 ] -> value instanceof \PhpParser\Node\Scalar\LNumber ) {
2018-10-08 05:19:10 +00:00
return ;
}
/** @var LNumber $limitNumberNode */
2019-02-22 17:25:31 +00:00
$limitNumberNode = $funcCall -> args [ 2 ] -> value ;
2018-10-08 05:19:10 +00:00
if ( $limitNumberNode -> value !== 0 ) {
return ;
}
$limitNumberNode -> value = 1 ;
}
2021-05-10 22:23:08 +00:00
private function createTernaryWithStrlenOfFirstMatch ( \PhpParser\Node\Expr\FuncCall $funcCall ) : \PhpParser\Node\Expr\Ternary
2018-10-08 05:19:10 +00:00
{
2021-05-10 22:23:08 +00:00
$arrayDimFetch = new \PhpParser\Node\Expr\ArrayDimFetch ( $funcCall -> args [ 2 ] -> value , new \PhpParser\Node\Scalar\LNumber ( 0 ));
2021-01-30 21:41:25 +00:00
$strlenFuncCall = $this -> nodeFactory -> createFuncCall ( 'strlen' , [ $arrayDimFetch ]);
2021-05-10 22:23:08 +00:00
return new \PhpParser\Node\Expr\Ternary ( $funcCall , $strlenFuncCall , $this -> nodeFactory -> createFalse ());
2018-10-08 05:19:10 +00:00
}
2021-05-09 20:15:43 +00:00
private function isCaseInsensitiveFunction ( string $functionName ) : bool
2018-10-31 15:34:37 +00:00
{
2021-05-29 22:10:59 +00:00
if ( \strpos ( $functionName , 'eregi' ) !== \false ) {
2021-05-09 20:15:43 +00:00
return \true ;
2018-10-31 15:34:37 +00:00
}
2021-05-29 22:10:59 +00:00
return \strpos ( $functionName , 'spliti' ) !== \false ;
2018-10-31 15:34:37 +00:00
}
2018-10-08 05:19:10 +00:00
}