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
36 changes: 36 additions & 0 deletions lib/PHPCfg/Op/Stmt/TraitUse.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

/**
* This file is part of PHP-CFG, a Control flow graph implementation for PHP
*
* @copyright 2015 Anthony Ferrara. All rights reserved
* @license MIT See LICENSE at the root of the project for more info
*/

namespace PHPCfg\Op\Stmt;

use PHPCfg\Op\Stmt;
use PhpCfg\Operand;
use PHPCfg\TraitUseAdaptation;

class TraitUse extends Stmt
{
/**
* @var Operand[]
*/
public array $traits;

/**
* @var TraitUseAdaptation[]
*/
public array $adaptations;

public function __construct(array $traits,array $adaptations, array $attributes = [])
{
parent::__construct($attributes);
$this->traits = $traits;
$this->adaptations = $adaptations;
}
}
30 changes: 30 additions & 0 deletions lib/PHPCfg/Op/TraitUseAdaptation.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);


/**
* This file is part of PHP-CFG, a Control flow graph implementation for PHP
*
* @copyright 2015 Anthony Ferrara. All rights reserved
* @license MIT See LICENSE at the root of the project for more info
*/

namespace PHPCfg\Op;

use PHPCfg\Op;
use PHPCfg\Operand;

abstract class TraitUseAdaptation extends Op
{
public ?Operand $trait;

public Operand $method;

public function __construct(?Operand $trait,Operand $method,array $attributes = [])
{
parent::__construct($attributes);
$this->trait = $trait;
$this->method = $method;
}
}
45 changes: 45 additions & 0 deletions lib/PHPCfg/Op/TraitUseAdaptation/Alias.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

declare(strict_types=1);

/**
* This file is part of PHP-CFG, a Control flow graph implementation for PHP
*
* @copyright 2015 Anthony Ferrara. All rights reserved
* @license MIT See LICENSE at the root of the project for more info
*/

namespace PHPCfg\Op\TraitUseAdaptation;

use PhpParser\Node;
use PHPCfg\Operand;
use PHPCfg\Op\TraitUseAdaptation;

class Alias extends TraitUseAdaptation
{
public ?Operand $newName;

public ?int $newModifier;

public function __construct(?Operand $trait,Operand $method,?Operand $newName,?int $newModifier,array $attributes = [])
{
parent::__construct($trait,$method,$attributes);
$this->newName = $newName;
$this->newModifier = $newModifier;
}

public function isPublic() : bool
{
return (bool) ($this->newModifier & Node\Stmt\Class_::MODIFIER_PUBLIC);
}

public function isProtected() : bool
{
return (bool) ($this->newModifier & Node\Stmt\Class_::MODIFIER_PROTECTED);
}

public function isPrivate() : bool
{
return (bool) ($this->newModifier & Node\Stmt\Class_::MODIFIER_PRIVATE);
}
}
26 changes: 26 additions & 0 deletions lib/PHPCfg/Op/TraitUseAdaptation/Precedence.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
<?php

declare(strict_types=1);

/**
* This file is part of PHP-CFG, a Control flow graph implementation for PHP
*
* @copyright 2015 Anthony Ferrara. All rights reserved
* @license MIT See LICENSE at the root of the project for more info
*/

namespace PHPCfg\Op\TraitUseAdaptation;

use PHPCfg\Operand;
use PHPCfg\Op\TraitUseAdaptation;

class Precedence extends TraitUseAdaptation
{
public array $insteadof;

public function __construct(?Operand $trait,Operand $method,array $insteadof,array $attributes = [])
{
parent::__construct($trait,$method,$attributes);
$this->insteadof = $insteadof;
}
}
33 changes: 32 additions & 1 deletion lib/PHPCfg/Parser.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@

use PHPCfg\Op\Stmt\Jump;
use PHPCfg\Op\Stmt\JumpIf;
use PHPCfg\Op\Stmt\TraitUse;
use PHPCfg\Op\Terminal\Return_;
use PHPCfg\Op\TraitUseAdaptation\Alias;
use PHPCfg\Op\TraitUseAdaptation\Precedence;
use PHPCfg\Operand\Literal;
use PHPCfg\Operand\Temporary;
use PHPCfg\Operand\Variable;
Expand Down Expand Up @@ -684,7 +687,35 @@ protected function parseStmt_Trait(Stmt\Trait_ $node)

protected function parseStmt_TraitUse(Stmt\TraitUse $node)
{
// TODO
$traits = [];
$adaptations = [];
foreach($node->traits as $trait_) {
$traits[] = new Literal($trait_->toCodeString());
}
foreach($node->adaptations as $adaptation) {
if($adaptation instanceof Stmt\TraitUseAdaptation\Alias) {
$adaptations[] = new Alias(
$adaptation->trait != null ? new Literal($adaptation->trait->toCodeString()) : null,
new Literal($adaptation->method->name),
$adaptation->newName != null ? new Literal($adaptation->newName->name) : null,
$adaptation->newModifier,
$this->mapAttributes($adaptation)
);
}
else if($adaptation instanceof Stmt\TraitUseAdaptation\Precedence) {
$insteadofs = [];
foreach($adaptation->insteadof as $insteadof) {
$insteadofs[] = new Literal($insteadof->toCodeString());
}
$adaptations[] = new Precedence(
$adaptation->trait != null ? new Literal($adaptation->trait->toCodeString()) : null,
new Literal($adaptation->method->name),
$insteadofs,
$this->mapAttributes($adaptation)
);
}
}
$this->block->children[] = new TraitUse($traits,$adaptations,$this->mapAttributes($node));
}

protected function parseStmt_TryCatch(Stmt\TryCatch $node)
Expand Down
39 changes: 39 additions & 0 deletions lib/PHPCfg/Printer.php
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,45 @@ protected function renderOp(Op $op)
$result .= "\n flags: " . $this->indent($this->renderFlags($op));
$result .= "\n declaredType: " . $this->indent($this->renderType($op->declaredType));
}
if($op instanceof Op\Stmt\TraitUse) {
foreach($op->traits as $index => $trait_) {
$result .= "\n use[$index]: " . $this->indent($this->renderOperand($trait_));
}
foreach($op->adaptations as $index => $adaptation) {
if($adaptation instanceof Op\TraitUseAdaptation\Alias) {
$result .= "\n adaptation[$index]: Alias";
if($adaptation->trait != null) {
$result .= "\n trait:".$this->indent($this->renderOperand($adaptation->trait));
}
$result .= "\n method:".$this->indent($this->renderOperand($adaptation->method));
if($adaptation->newName != null) {
$result .= "\n newName:".$this->indent($this->renderOperand($adaptation->newName));
}
if($adaptation->newModifier != null) {
$result .= "\n newModifier:";
if($adaptation->isPublic()) {
$result .= "public";
}
if($adaptation->isPrivate()) {
$result .= "private";
}
if($adaptation->isProtected()) {
$result .= "protected";
}
}
}
else if($adaptation instanceof Op\TraitUseAdaptation\Precedence) {
$result .= "\n adaptation[$index]: Insteadof";
if($adaptation->trait != null) {
$result .= "\n trait:".$this->indent($this->renderOperand($adaptation->trait));
}
$result .= "\n method:".$this->indent($this->renderOperand($adaptation->method));
foreach($adaptation->insteadof as $index2 => $insteadof) {
$result .= "\n insteadof[$index2]: " . $this->indent($this->renderOperand($insteadof));
}
}
}
}
if ($op instanceof Op\Stmt\ClassMethod) {
$result .= "\n flags: " . $this->indent($this->renderFlags($op));
}
Expand Down
115 changes: 115 additions & 0 deletions test/code/traitUse.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
<?php
trait A {
public function smallTalk() {
echo 'a';
}
public function bigTalk() {
echo 'A';
}
}

trait B {
public function smallTalk() {
echo 'b';
}
public function bigTalk() {
echo 'B';
}
}

class Talker {
use A, B {
B::smallTalk insteadof A;
A::bigTalk insteadof B;
}
}

class Aliased_Talker {
use A, B {
B::smallTalk insteadof A;
A::bigTalk insteadof B;
B::bigTalk as private talk;
}
}
-----
Block#1
Stmt_Trait
name: LITERAL('A')
stmts: Block#2
Stmt_Trait
name: LITERAL('B')
stmts: Block#3
Stmt_Class
name: LITERAL('Talker')
stmts: Block#4
Stmt_Class
name: LITERAL('Aliased_Talker')
stmts: Block#5
Terminal_Return

Block#2
Stmt_ClassMethod<'smallTalk'>
flags: public
Stmt_ClassMethod<'bigTalk'>
flags: public

Block#3
Stmt_ClassMethod<'smallTalk'>
flags: public
Stmt_ClassMethod<'bigTalk'>
flags: public

Block#4
Stmt_TraitUse
use[0]: LITERAL('\\A')
use[1]: LITERAL('\\B')
adaptation[0]: Insteadof
trait:LITERAL('\\B')
method:LITERAL('smallTalk')
insteadof[0]: LITERAL('\\A')
adaptation[1]: Insteadof
trait:LITERAL('\\A')
method:LITERAL('bigTalk')
insteadof[0]: LITERAL('\\B')

Block#5
Stmt_TraitUse
use[0]: LITERAL('\\A')
use[1]: LITERAL('\\B')
adaptation[0]: Insteadof
trait:LITERAL('\\B')
method:LITERAL('smallTalk')
insteadof[0]: LITERAL('\\A')
adaptation[1]: Insteadof
trait:LITERAL('\\A')
method:LITERAL('bigTalk')
insteadof[0]: LITERAL('\\B')
adaptation[2]: Alias
trait:LITERAL('\\B')
method:LITERAL('bigTalk')
newName:LITERAL('talk')
newModifier:private

Function 'A::smallTalk': mixed
Block#1
Terminal_Echo
expr: LITERAL('a')
Terminal_Return

Function 'A::bigTalk': mixed
Block#1
Terminal_Echo
expr: LITERAL('A')
Terminal_Return

Function 'B::smallTalk': mixed
Block#1
Terminal_Echo
expr: LITERAL('b')
Terminal_Return

Function 'B::bigTalk': mixed
Block#1
Terminal_Echo
expr: LITERAL('B')
Terminal_Return
Loading