2019-10-13 05:59:52 +00:00
< ? php
2021-05-09 20:15:43 +00:00
declare ( strict_types = 1 );
2020-07-27 08:16:16 +00:00
namespace Rector\CodeQuality\Rector\FuncCall ;
2019-01-02 16:02:47 +00:00
use PhpParser\Node ;
use PhpParser\Node\Arg ;
use PhpParser\Node\Expr ;
use PhpParser\Node\Expr\Assign ;
2021-02-23 01:25:34 +00:00
use PhpParser\Node\Expr\Cast ;
2019-01-02 16:02:47 +00:00
use PhpParser\Node\Expr\Cast\Array_ ;
use PhpParser\Node\Expr\Cast\Bool_ ;
use PhpParser\Node\Expr\Cast\Double ;
use PhpParser\Node\Expr\Cast\Int_ ;
use PhpParser\Node\Expr\Cast\Object_ ;
use PhpParser\Node\Expr\Cast\String_ ;
use PhpParser\Node\Expr\FuncCall ;
use PhpParser\Node\Stmt\Expression ;
2021-09-27 15:43:15 +00:00
use Rector\Core\NodeAnalyzer\ArgsAnalyzer ;
2020-02-06 21:48:18 +00:00
use Rector\Core\Rector\AbstractRector ;
2019-04-13 09:20:27 +00:00
use Rector\NodeTypeResolver\Node\AttributeKey ;
2020-11-16 17:50:38 +00:00
use Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample ;
use Symplify\RuleDocGenerator\ValueObject\RuleDefinition ;
2019-01-02 16:02:47 +00:00
/**
2021-04-10 18:47:17 +00:00
* @ changelog https :// stackoverflow . com / questions / 5577003 / using - settype - in - php - instead - of - typecasting - using - brackets - what - is - the - differen / 5577068 #5577068
*
2021-03-12 22:20:25 +00:00
* @ see \Rector\Tests\CodeQuality\Rector\FuncCall\SetTypeToCastRector\SetTypeToCastRectorTest
2019-01-02 16:02:47 +00:00
*/
2021-05-10 22:23:08 +00:00
final class SetTypeToCastRector extends \Rector\Core\Rector\AbstractRector
2019-01-02 16:02:47 +00:00
{
/**
2021-02-23 01:25:34 +00:00
* @ var array < string , class - string < Cast >>
2019-01-02 16:02:47 +00:00
*/
2021-05-10 22:23:08 +00:00
private const TYPE_TO_CAST = [ 'array' => \PhpParser\Node\Expr\Cast\Array_ :: class , 'bool' => \PhpParser\Node\Expr\Cast\Bool_ :: class , 'boolean' => \PhpParser\Node\Expr\Cast\Bool_ :: class , 'double' => \PhpParser\Node\Expr\Cast\Double :: class , 'float' => \PhpParser\Node\Expr\Cast\Double :: class , 'int' => \PhpParser\Node\Expr\Cast\Int_ :: class , 'integer' => \PhpParser\Node\Expr\Cast\Int_ :: class , 'object' => \PhpParser\Node\Expr\Cast\Object_ :: class , 'string' => \PhpParser\Node\Expr\Cast\String_ :: class ];
2021-09-27 15:43:15 +00:00
/**
2021-12-04 12:47:17 +00:00
* @ readonly
2021-09-27 15:43:15 +00:00
* @ var \Rector\Core\NodeAnalyzer\ArgsAnalyzer
*/
private $argsAnalyzer ;
public function __construct ( \Rector\Core\NodeAnalyzer\ArgsAnalyzer $argsAnalyzer )
{
$this -> argsAnalyzer = $argsAnalyzer ;
}
2021-05-10 22:23:08 +00:00
public function getRuleDefinition () : \Symplify\RuleDocGenerator\ValueObject\RuleDefinition
2019-01-02 16:02:47 +00:00
{
2021-05-10 22:23:08 +00:00
return new \Symplify\RuleDocGenerator\ValueObject\RuleDefinition ( 'Changes settype() to (type) where possible' , [ new \Symplify\RuleDocGenerator\ValueObject\CodeSample\CodeSample ( <<< 'CODE_SAMPLE'
2019-01-02 16:02:47 +00:00
class SomeClass
{
public function run ( $foo )
{
settype ( $foo , 'string' );
return settype ( $foo , 'integer' );
}
}
2020-09-15 08:23:13 +00:00
CODE_SAMPLE
2021-05-09 20:15:43 +00:00
, <<< 'CODE_SAMPLE'
2019-01-02 16:02:47 +00:00
class SomeClass
{
2021-07-28 12:55:48 +00:00
public function run ( $foo )
2019-01-02 16:02:47 +00:00
{
$foo = ( string ) $foo ;
return ( int ) $foo ;
}
}
2020-09-15 08:23:13 +00:00
CODE_SAMPLE
2021-05-09 20:15:43 +00:00
)]);
2019-01-02 16:02:47 +00:00
}
/**
2021-02-27 00:06:15 +00:00
* @ return array < class - string < Node >>
2019-01-02 16:02:47 +00:00
*/
2021-05-09 20:15:43 +00:00
public function getNodeTypes () : array
2019-01-02 16:02:47 +00:00
{
2021-05-10 22:23:08 +00:00
return [ \PhpParser\Node\Expr\FuncCall :: class ];
2019-01-02 16:02:47 +00:00
}
/**
2021-12-10 09:57:54 +00:00
* @ param \PhpParser\Node $node
2019-01-02 16:02:47 +00:00
*/
2021-12-10 09:57:54 +00:00
public function refactor ( $node ) : ? \PhpParser\Node
2019-01-02 16:02:47 +00:00
{
2021-05-09 20:15:43 +00:00
if ( ! $this -> isName ( $node , 'settype' )) {
2019-01-02 16:02:47 +00:00
return null ;
}
2021-09-27 15:43:15 +00:00
if ( ! $this -> argsAnalyzer -> isArgInstanceInArgsPosition ( $node -> args , 1 )) {
return null ;
}
/** @var Arg $secondArg */
$secondArg = $node -> args [ 1 ];
$typeNode = $this -> valueResolver -> getValue ( $secondArg -> value );
2019-01-02 16:02:47 +00:00
if ( $typeNode === null ) {
return null ;
}
2021-05-09 20:15:43 +00:00
$typeNode = \strtolower ( $typeNode );
2021-09-27 15:43:15 +00:00
if ( ! $this -> argsAnalyzer -> isArgInstanceInArgsPosition ( $node -> args , 0 )) {
return null ;
}
/** @var Arg $firstArg */
$firstArg = $node -> args [ 0 ];
$varNode = $firstArg -> value ;
2021-05-10 22:23:08 +00:00
$parentNode = $node -> getAttribute ( \Rector\NodeTypeResolver\Node\AttributeKey :: PARENT_NODE );
2019-01-02 16:02:47 +00:00
// result of function or probably used
2021-05-10 22:23:08 +00:00
if ( $parentNode instanceof \PhpParser\Node\Expr || $parentNode instanceof \PhpParser\Node\Arg ) {
2019-01-02 16:02:47 +00:00
return null ;
}
if ( isset ( self :: TYPE_TO_CAST [ $typeNode ])) {
$castClass = self :: TYPE_TO_CAST [ $typeNode ];
$castNode = new $castClass ( $varNode );
2021-05-10 22:23:08 +00:00
if ( $parentNode instanceof \PhpParser\Node\Stmt\Expression ) {
2019-01-02 16:02:47 +00:00
// bare expression? → assign
2021-05-10 22:23:08 +00:00
return new \PhpParser\Node\Expr\Assign ( $varNode , $castNode );
2019-01-02 16:02:47 +00:00
}
return $castNode ;
}
if ( $typeNode === 'null' ) {
2021-05-10 22:23:08 +00:00
return new \PhpParser\Node\Expr\Assign ( $varNode , $this -> nodeFactory -> createNull ());
2019-01-02 16:02:47 +00:00
}
return $node ;
}
}