Compare commits
1 Commits
master
...
optimisati
Author | SHA1 | Date |
---|---|---|
|
81fc8a62b5 | 1 year ago |
File diff suppressed because it is too large
Load Diff
@ -1,23 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
use classes\Administrator;
|
|
||||||
|
|
||||||
final class testAdministrator extends TestCase
|
|
||||||
{
|
|
||||||
public function testInstanciation()
|
|
||||||
{
|
|
||||||
$admin = new Administrator(1, "admin", "admin");
|
|
||||||
$this->assertInstanceOf(Administrator::class, $admin);
|
|
||||||
$this->assertEquals(1, $admin->getId());
|
|
||||||
$this->assertEquals("admin", $admin->getUsername());
|
|
||||||
$this->assertTrue(password_verify("admin", $admin->getHashedPassword()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testSetHashedPassword()
|
|
||||||
{
|
|
||||||
$admin = new Administrator(1, "admin", "admin");
|
|
||||||
$admin->setHashedPassword(password_hash("bobby", PASSWORD_BCRYPT));
|
|
||||||
$this->assertTrue(password_verify("bobby", $admin->getHashedPassword()));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
use classes\Answer;
|
|
||||||
|
|
||||||
final class testAnswer extends TestCase
|
|
||||||
{
|
|
||||||
public function testInstanciation()
|
|
||||||
{
|
|
||||||
$answer = new Answer(1, "content", 1);
|
|
||||||
$this->assertInstanceOf(Answer::class, $answer);
|
|
||||||
$this->assertEquals(1, $answer->getId());
|
|
||||||
$this->assertEquals("content", $answer->getContent());
|
|
||||||
$this->assertEquals(1, $answer->getIdQuestion());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testSetContent()
|
|
||||||
{
|
|
||||||
$answer = new Answer(1, "content", 1);
|
|
||||||
$answer->setContent("new content");
|
|
||||||
$this->assertEquals("new content", $answer->getContent());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,15 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
use classes\Chapter;
|
|
||||||
|
|
||||||
final class testChapter extends TestCase
|
|
||||||
{
|
|
||||||
public function testInstanciation()
|
|
||||||
{
|
|
||||||
$chapter = new Chapter(1, "chapter 1");
|
|
||||||
$this->assertInstanceOf(Chapter::class, $chapter);
|
|
||||||
$this->assertEquals(1, $chapter->getId());
|
|
||||||
$this->assertEquals("chapter 1", $chapter->getName());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
use classes\Lobby;
|
|
||||||
|
|
||||||
final class testLobby extends TestCase
|
|
||||||
{
|
|
||||||
public function testInstanciation()
|
|
||||||
{
|
|
||||||
$lobby = new Lobby(1, "lobby", "password", 1);
|
|
||||||
$this->assertInstanceOf(Lobby::class, $lobby);
|
|
||||||
$this->assertEquals(1, $lobby->getId());
|
|
||||||
$this->assertEquals("lobby", $lobby->getName());
|
|
||||||
$this->assertEquals("password", $lobby->getPassword());
|
|
||||||
$this->assertEquals(1, $lobby->getNbPlayers());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testSetter()
|
|
||||||
{
|
|
||||||
$lobby = new Lobby(1, "lobby", "password", 1);
|
|
||||||
$lobby->setNbplayers(2);
|
|
||||||
$this->assertEquals(2, $lobby->getNbPlayers());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
use classes\Player;
|
|
||||||
|
|
||||||
final class testPlayer extends TestCase
|
|
||||||
{
|
|
||||||
public function testInstanciation()
|
|
||||||
{
|
|
||||||
$player = new Player(1, "player", "player");
|
|
||||||
$this->assertInstanceOf(Player::class, $player);
|
|
||||||
$this->assertEquals(1, $player->getId());
|
|
||||||
$this->assertEquals("player", $player->getNickname());
|
|
||||||
$this->assertTrue(password_verify("player", $player->getHashedPassword()));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testSetter()
|
|
||||||
{
|
|
||||||
$player = new Player(1, "player", "player");
|
|
||||||
$player->setHashedPassword("bobby");
|
|
||||||
$this->assertTrue(password_verify("bobby", $player->getHashedPassword()));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
use classes\Question;
|
|
||||||
|
|
||||||
final class testQuestion extends TestCase
|
|
||||||
{
|
|
||||||
public function testInstanciation()
|
|
||||||
{
|
|
||||||
$question = new Question(1, "question", 1);
|
|
||||||
$this->assertInstanceOf(Question::class, $question);
|
|
||||||
$this->assertEquals(1, $question->getId());
|
|
||||||
$this->assertEquals("question", $question->getContent());
|
|
||||||
$this->assertEquals(1, $question->getIdChapter());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testSetter()
|
|
||||||
{
|
|
||||||
$question = new Question(1, "question", 1);
|
|
||||||
$question->setContent("new question");
|
|
||||||
$this->assertEquals("new question", $question->getContent());
|
|
||||||
$question->setDifficulty(2);
|
|
||||||
$this->assertEquals(2, $question->getDifficulty());
|
|
||||||
$question->setIdAnswerGood(2);
|
|
||||||
$this->assertEquals(2, $question->getIdAnswerGood());
|
|
||||||
$question->setNbFails(3);
|
|
||||||
$this->assertEquals(3, $question->getNbFails());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,58 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
use gateways\GatewayAdministrator;
|
|
||||||
|
|
||||||
use function PHPUnit\Framework\assertEquals;
|
|
||||||
|
|
||||||
final class testAdministrators extends TestCase
|
|
||||||
{
|
|
||||||
public function testGetAdministratorByUsername()
|
|
||||||
{
|
|
||||||
$gateway = new GatewayAdministrator();
|
|
||||||
$response = $gateway->getAdministratorByUsername("admin");
|
|
||||||
assertEquals($response['username'], "admin");
|
|
||||||
assertEquals($response['id'], "42");
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetAdministratorByID()
|
|
||||||
{
|
|
||||||
$gateway = new GatewayAdministrator();
|
|
||||||
$response = $gateway->getAdministratorByID(42);
|
|
||||||
assertEquals($response['id'], "42");
|
|
||||||
assertEquals($response['username'], "admin");
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetAdministrators()
|
|
||||||
{
|
|
||||||
$gateway = new GatewayAdministrator();
|
|
||||||
$response = $gateway->getAdministrators();
|
|
||||||
assertEquals($response[0]['id'], "42");
|
|
||||||
assertEquals($response[0]['username'], "admin");
|
|
||||||
assertEquals($response[1]['id'], "121");
|
|
||||||
assertEquals($response[1]['username'], "testadmin");
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testUpdateAdministrator()
|
|
||||||
{
|
|
||||||
$gateway = new GatewayAdministrator();
|
|
||||||
$gateway->updateAdministrator(1, ["username" => "test", "password" => "test"]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testAddAndDeleteAdministrator()
|
|
||||||
{
|
|
||||||
|
|
||||||
$gateway = new GatewayAdministrator();
|
|
||||||
$gateway->addAdministrator(["username" => "test", "password" => "test"]);
|
|
||||||
$response = $gateway->getAdministratorByUsername("test");
|
|
||||||
assertEquals($response['username'], "test");
|
|
||||||
$gateway->deleteAdministratorByID($gateway->getAdministratorByUsername("test")['id']);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testVerifyAdministrator()
|
|
||||||
{
|
|
||||||
$gateway = new GatewayAdministrator();
|
|
||||||
$response = $gateway->verifyAdministrator(["username" => "testadmin", "password" => '123456']);
|
|
||||||
assertEquals(121, $response['id']);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,61 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
use gateways\GatewayAnswer;
|
|
||||||
|
|
||||||
use function PHPUnit\Framework\assertEquals;
|
|
||||||
use function PHPUnit\Framework\assertNotEquals;
|
|
||||||
|
|
||||||
class testAnswers extends TestCase
|
|
||||||
{
|
|
||||||
public function testAddAnswer()
|
|
||||||
{
|
|
||||||
$gateway = new GatewayAnswer();
|
|
||||||
$answer = array(
|
|
||||||
'content' => 'This is a test answer',
|
|
||||||
'idquestion' => 2
|
|
||||||
);
|
|
||||||
$answerId = $gateway->addAnswer($answer);
|
|
||||||
assertNotEquals($answerId, null);
|
|
||||||
$gateway->deleteAnswer($answerId);
|
|
||||||
$answerId = $gateway->getAnswerByID($answerId);
|
|
||||||
assertEquals($answerId, null);
|
|
||||||
$gateway->deleteAnswer($answerId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetAnswerByID()
|
|
||||||
{
|
|
||||||
$gateway = new GatewayAnswer();
|
|
||||||
$answer = $gateway->getAnswerByID(5);
|
|
||||||
assertEquals($answer['content'], '4');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetAnswersByIDQuestions()
|
|
||||||
{
|
|
||||||
$gateway = new GatewayAnswer();
|
|
||||||
$answers = $gateway->getAnswersByIDQuestions(2);
|
|
||||||
assertEquals($answers[0]['content'], '4');
|
|
||||||
assertEquals($answers[1]['content'], '-4');
|
|
||||||
assertEquals($answers[2]['content'], 'on ne peut pas simplifier');
|
|
||||||
assertEquals($answers[3]['content'], '1');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testUpdateAnswer()
|
|
||||||
{
|
|
||||||
$gateway = new GatewayAnswer();
|
|
||||||
$answer = array(
|
|
||||||
'content' => 'This is a test answer',
|
|
||||||
'idquestion' => 2
|
|
||||||
);
|
|
||||||
$answerId = $gateway->addAnswer($answer);
|
|
||||||
$answer = array(
|
|
||||||
'id' => $answerId,
|
|
||||||
'content' => 'This is a test answer updated',
|
|
||||||
'idquestion' => 2
|
|
||||||
);
|
|
||||||
$gateway->updateAnswer($answerId, $answer);
|
|
||||||
$answer = $gateway->getAnswerByID($answerId);
|
|
||||||
assertEquals($answer['content'], 'This is a test answer updated');
|
|
||||||
$gateway->deleteAnswer($answerId);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,65 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
use gateways\GatewayChapter;
|
|
||||||
|
|
||||||
use function PHPUnit\Framework\assertEquals;
|
|
||||||
use function PHPUnit\Framework\assertNotEquals;
|
|
||||||
|
|
||||||
class testChapters extends TestCase
|
|
||||||
{
|
|
||||||
public function testAddChapter()
|
|
||||||
{
|
|
||||||
$gateway = new GatewayChapter();
|
|
||||||
$chapter = array(
|
|
||||||
'name' => 'This is a test chapter',
|
|
||||||
'idcourse' => 1
|
|
||||||
);
|
|
||||||
$chapterId = $gateway->addChapter($chapter);
|
|
||||||
assertNotEquals($chapterId, null);
|
|
||||||
$gateway->deleteChapter($chapterId);
|
|
||||||
$chapter = $gateway->getChapterByID($chapterId);
|
|
||||||
assertEquals($chapter, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetChapters()
|
|
||||||
{
|
|
||||||
$gateway = new GatewayChapter();
|
|
||||||
$chapters = $gateway->getChapters();
|
|
||||||
assertEquals($chapters[0]['name'], 'Calculs algébrique et littéral ');
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testUpdateChapter()
|
|
||||||
{
|
|
||||||
$gateway = new GatewayChapter();
|
|
||||||
$chapter = array(
|
|
||||||
'name' => 'This is a test chapter',
|
|
||||||
'idcourse' => 1
|
|
||||||
);
|
|
||||||
$chapterId = $gateway->addChapter($chapter);
|
|
||||||
$chapter = array(
|
|
||||||
'id' => $chapterId,
|
|
||||||
'name' => 'This is a test chapter updated',
|
|
||||||
'idcourse' => 1
|
|
||||||
);
|
|
||||||
$gateway->updateChapter($chapterId, $chapter);
|
|
||||||
$chapter = $gateway->getChapterByID($chapterId);
|
|
||||||
assertEquals($chapter['name'], 'This is a test chapter updated');
|
|
||||||
$gateway->deleteChapter($chapterId);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testVerifyChapter()
|
|
||||||
{
|
|
||||||
$gateway = new GatewayChapter();
|
|
||||||
$chapter = array(
|
|
||||||
'name' => 'This is a test chapter',
|
|
||||||
'idcourse' => 1
|
|
||||||
);
|
|
||||||
$chapterId = $gateway->addChapter($chapter);
|
|
||||||
$chapter = $gateway->getChapterByID($chapterId);
|
|
||||||
assertEquals($gateway->verifyChapterByID($chapterId)['id'], $chapterId);
|
|
||||||
assertEquals($gateway->verifyChapterByName("This is a test chapter")['id'], $chapterId);
|
|
||||||
$gateway->deleteChapter($chapterId);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,105 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
use gateways\GatewayJouer;
|
|
||||||
use gateways\GatewayPlayer;
|
|
||||||
use gateways\GatewayChapter;
|
|
||||||
|
|
||||||
use classes\Player;
|
|
||||||
|
|
||||||
use function PHPUnit\Framework\assertEquals;
|
|
||||||
use function PHPUnit\Framework\assertNotEquals;
|
|
||||||
|
|
||||||
class testJouer extends TestCase
|
|
||||||
{
|
|
||||||
public function testAddJouer()
|
|
||||||
{
|
|
||||||
|
|
||||||
$playerArray = [];
|
|
||||||
$playerArray['id'] = 1;
|
|
||||||
$playerArray['nickname'] = "testUnit";
|
|
||||||
$playerArray['password'] = "testUnit";
|
|
||||||
$chapterArray = [];
|
|
||||||
$chapterArray['id'] = 1;
|
|
||||||
$chapterArray['name'] = "testUnit";
|
|
||||||
$gwayChapter = new GatewayChapter();
|
|
||||||
$gwayPlayer = new GatewayPlayer();
|
|
||||||
|
|
||||||
$gatewayAnswer = $gwayPlayer->getPlayerByNickname("testUnit");
|
|
||||||
if ($gatewayAnswer) {
|
|
||||||
$gwayPlayer->deletePlayerByID($gatewayAnswer['id']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$gatewayAnswer = $gwayChapter->verifyChapterByName("testUnit");
|
|
||||||
if ($gatewayAnswer) {
|
|
||||||
$gwayChapter->deleteChapter($gatewayAnswer['id']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$gwayChapter->addChapter($chapterArray);
|
|
||||||
$gwayPlayer->addPlayer($playerArray);
|
|
||||||
$playerFromGWay = $gwayPlayer->getPlayerByNickname("testUnit");
|
|
||||||
$chapterFromGWay = $gwayChapter->verifyChapterByName("testUnit");
|
|
||||||
|
|
||||||
$gway = new GatewayJouer();
|
|
||||||
$gway->addJouer(
|
|
||||||
array(
|
|
||||||
'idchapter' => $chapterFromGWay['id'],
|
|
||||||
'idplayer' => $playerFromGWay['id'],
|
|
||||||
'maxscore' => 0
|
|
||||||
)
|
|
||||||
);
|
|
||||||
$maxScore = $gway->getMaxScoreByPlayerAndChapter(
|
|
||||||
array(
|
|
||||||
'idchapter' => $chapterFromGWay['id'],
|
|
||||||
'idplayer' => $playerFromGWay['id']
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assertEquals(0, $maxScore['maxscore']);
|
|
||||||
|
|
||||||
$gway->updateJouer(
|
|
||||||
array(
|
|
||||||
'idchapter' => $chapterFromGWay['id'],
|
|
||||||
'idplayer' => $playerFromGWay['id'],
|
|
||||||
'maxscore' => 10
|
|
||||||
)
|
|
||||||
);
|
|
||||||
$maxScore = $gway->getMaxScoreByPlayerAndChapter(
|
|
||||||
array(
|
|
||||||
'idchapter' => $chapterFromGWay['id'],
|
|
||||||
'idplayer' => $playerFromGWay['id']
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assertEquals(10, $maxScore['maxscore']);
|
|
||||||
|
|
||||||
$jouer = $gway->verifyJouer(
|
|
||||||
array(
|
|
||||||
'idchapter' => $chapterFromGWay['id'],
|
|
||||||
'idplayer' => $playerFromGWay['id']
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assertEquals($chapterFromGWay['id'], $jouer['idchapter']);
|
|
||||||
assertEquals($playerFromGWay['id'], $jouer['idplayer']);
|
|
||||||
|
|
||||||
$player = new Player($playerFromGWay['id'], $playerFromGWay['nickname'], "testUnit");
|
|
||||||
$maxScoreAndChapter = $gway->getMaxScoresWithChapter($player);
|
|
||||||
assertEquals(10, $maxScoreAndChapter[0]['maxscore']);
|
|
||||||
assertEquals($chapterFromGWay['id'], $maxScoreAndChapter[0]['idchapter']);
|
|
||||||
|
|
||||||
$gway->deleteJouer(
|
|
||||||
array(
|
|
||||||
'idchapter' => $chapterFromGWay['id'],
|
|
||||||
'idplayer' => $playerFromGWay['id']
|
|
||||||
)
|
|
||||||
);
|
|
||||||
$jouer = $gway->verifyJouer(
|
|
||||||
array(
|
|
||||||
'idchapter' => $chapterFromGWay['id'],
|
|
||||||
'idplayer' => $playerFromGWay['id']
|
|
||||||
)
|
|
||||||
);
|
|
||||||
assertEquals(false, $jouer);
|
|
||||||
$gwayPlayer->deletePlayerByID($playerFromGWay['id']);
|
|
||||||
$gwayChapter->deleteChapter($chapterFromGWay['id']);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,64 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
use gateways\GatewayLobby;
|
|
||||||
use classes\Lobby;
|
|
||||||
|
|
||||||
use function PHPUnit\Framework\assertEquals;
|
|
||||||
use function PHPUnit\Framework\assertNotEquals;
|
|
||||||
|
|
||||||
class testLobby extends TestCase
|
|
||||||
{
|
|
||||||
public function testAddLobby()
|
|
||||||
{
|
|
||||||
$lobby = new Lobby(1, "testUnit", "testUnit", 1);
|
|
||||||
$gateway = new GatewayLobby();
|
|
||||||
$gateway->deleteLobby($gateway->getLobbyByName("testUnit"));
|
|
||||||
$gateway->addLobby($lobby);
|
|
||||||
$lobbyArray = $gateway->getLobbyByName("testUnit");
|
|
||||||
$lobby2 = new Lobby($lobbyArray['id'], $lobbyArray['name'], $lobbyArray['password'], $lobbyArray['nbplayers']);
|
|
||||||
assertEquals($lobby->getId(), $lobby2->getId());
|
|
||||||
assertEquals($lobby->getName(), $lobby2->getName());
|
|
||||||
assertEquals($lobby->getPassword(), $lobby2->getPassword());
|
|
||||||
assertEquals($lobby->getNbPlayers(), $lobby2->getNbPlayers());
|
|
||||||
$gateway->deleteLobby($lobby->getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetLobbies()
|
|
||||||
{
|
|
||||||
$gateway = new GatewayLobby();
|
|
||||||
$lobbies = $gateway->getLobbies();
|
|
||||||
assertNotEquals(0, count($lobbies));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetLobbyByName()
|
|
||||||
{
|
|
||||||
$lobby = new Lobby(1, "testUnit", "testUnit", 1);
|
|
||||||
$gateway = new GatewayLobby();
|
|
||||||
$gateway->deleteLobby($gateway->getLobbyByName("testUnit"));
|
|
||||||
$gateway->addLobby($lobby);
|
|
||||||
$lobbyArray = $gateway->getLobbyByName("testUnit");
|
|
||||||
$lobby2 = new Lobby(
|
|
||||||
$lobbyArray['id'],
|
|
||||||
$lobbyArray['name'],
|
|
||||||
$lobbyArray['password'],
|
|
||||||
$lobbyArray['nbplayers']
|
|
||||||
);
|
|
||||||
assertEquals($lobby->getId(), $lobby2->getId());
|
|
||||||
assertEquals($lobby->getName(), $lobby2->getName());
|
|
||||||
assertEquals($lobby->getPassword(), $lobby2->getPassword());
|
|
||||||
assertEquals($lobby->getNbPlayers(), $lobby2->getNbPlayers());
|
|
||||||
$gateway->deleteLobby($lobby->getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testDeleteLobby()
|
|
||||||
{
|
|
||||||
$lobby = new Lobby(1, "testUnit", "testUnit", 1);
|
|
||||||
$gateway = new GatewayLobby();
|
|
||||||
$gateway->deleteLobby($gateway->getLobbyByName("testUnit"));
|
|
||||||
$gateway->addLobby($lobby);
|
|
||||||
$gateway->deleteLobby($lobby->getId());
|
|
||||||
$lobby2 = $gateway->getLobbyByName("testUnit");
|
|
||||||
assertEquals(false, $lobby2);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,72 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
use gateways\GatewayPlayer;
|
|
||||||
use classes\Player;
|
|
||||||
|
|
||||||
use function PHPUnit\Framework\assertEquals;
|
|
||||||
use function PHPUnit\Framework\assertNotEquals;
|
|
||||||
|
|
||||||
class testPlayer extends TestCase
|
|
||||||
{
|
|
||||||
public function testAddPlayer()
|
|
||||||
{
|
|
||||||
$player = [];
|
|
||||||
$player['id'] = 1;
|
|
||||||
$player['nickname'] = "testUnit";
|
|
||||||
$player['password'] = "testUnit";
|
|
||||||
$gateway = new GatewayPlayer();
|
|
||||||
$gatewayAnswer = $gateway->getPlayerByNickname("testUnit");
|
|
||||||
if ($gatewayAnswer) {
|
|
||||||
$gateway->deletePlayerByID($gatewayAnswer['id']);
|
|
||||||
}
|
|
||||||
$gateway->addPlayer($player);
|
|
||||||
$player2 = $gateway->getPlayerByNickname("testUnit");
|
|
||||||
assertEquals($player['nickname'], $player2['nickname']);
|
|
||||||
$gateway->deletePlayerByID($player['id']);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetPlayers()
|
|
||||||
{
|
|
||||||
$gateway = new GatewayPlayer();
|
|
||||||
$players = $gateway->getPlayers();
|
|
||||||
assertNotEquals(0, count($players));
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testGetPlayerByNickname()
|
|
||||||
{
|
|
||||||
$player = [];
|
|
||||||
$player['id'] = 1;
|
|
||||||
$player['nickname'] = "testUnit";
|
|
||||||
$player['password'] = "testUnit";
|
|
||||||
$gateway = new GatewayPlayer();
|
|
||||||
$gatewayAnswer = $gateway->getPlayerByNickname("testUnit");
|
|
||||||
if ($gatewayAnswer) {
|
|
||||||
$gateway->deletePlayerByID($gatewayAnswer['id']);
|
|
||||||
}
|
|
||||||
$gateway->addPlayer($player);
|
|
||||||
$player2 = $gateway->getPlayerByNickname("testUnit");
|
|
||||||
assertEquals($player['nickname'], $player2['nickname']);
|
|
||||||
$gateway->deletePlayerByID($player['id']);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function testDeletePlayer()
|
|
||||||
{
|
|
||||||
$player = [];
|
|
||||||
$player['id'] = 1;
|
|
||||||
$player['nickname'] = "testUnit";
|
|
||||||
$player['password'] = "testUnit";
|
|
||||||
$gateway = new GatewayPlayer();
|
|
||||||
$gatewayAnswer = $gateway->getPlayerByNickname("testUnit");
|
|
||||||
if ($gatewayAnswer) {
|
|
||||||
$gateway->deletePlayerByID($gatewayAnswer['id']);
|
|
||||||
}
|
|
||||||
$gateway->addPlayer($player);
|
|
||||||
$gatewayAnswer = $gateway->getPlayerByNickname("testUnit");
|
|
||||||
if ($gatewayAnswer) {
|
|
||||||
$gateway->deletePlayerByID($gatewayAnswer['id']);
|
|
||||||
}
|
|
||||||
$player2 = $gateway->getPlayerByNickname("testUnit");
|
|
||||||
assertEquals(false, $player2);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,98 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
use PHPUnit\Framework\TestCase;
|
|
||||||
use gateways\GatewayQuestion;
|
|
||||||
use gateways\GatewayAnswer;
|
|
||||||
|
|
||||||
use classes\Question;
|
|
||||||
|
|
||||||
use function PHPUnit\Framework\assertEquals;
|
|
||||||
use function PHPUnit\Framework\assertNotEquals;
|
|
||||||
|
|
||||||
class testQuestion extends TestCase
|
|
||||||
{
|
|
||||||
public function testQuestions()
|
|
||||||
{
|
|
||||||
|
|
||||||
$question = [];
|
|
||||||
$question['id'] = 1;
|
|
||||||
$question['content'] = "test Unit_";
|
|
||||||
$question['idchapter'] = 1;
|
|
||||||
$question['difficulty'] = 1;
|
|
||||||
$question['nbfails'] = 0;
|
|
||||||
|
|
||||||
$gateway = new GatewayQuestion();
|
|
||||||
$lenght = count($gateway->getQuestions());
|
|
||||||
$lenght2 = count($gateway->getQuestionsByChapterAndDifficulty(1, 1));
|
|
||||||
$question['id'] = $gateway->addQuestion($question);
|
|
||||||
|
|
||||||
$gwayAnswer = new GatewayAnswer();
|
|
||||||
$answer = array(
|
|
||||||
'content' => 'This is a test answer',
|
|
||||||
'idquestion' => $question['id']
|
|
||||||
);
|
|
||||||
$answer2 = array(
|
|
||||||
'content' => 'This is a test answer 2',
|
|
||||||
'idquestion' => $question['id']
|
|
||||||
);
|
|
||||||
$answer3 = array(
|
|
||||||
'content' => 'This is a test answer 3',
|
|
||||||
'idquestion' => $question['id']
|
|
||||||
);
|
|
||||||
$answer4 = array(
|
|
||||||
'content' => 'This is a test answer 4',
|
|
||||||
'idquestion' => $question['id']
|
|
||||||
);
|
|
||||||
$answerId1 = $gwayAnswer->addAnswer($answer);
|
|
||||||
$answerId2 = $gwayAnswer->addAnswer($answer2);
|
|
||||||
$answerId3 = $gwayAnswer->addAnswer($answer3);
|
|
||||||
$answerId4 = $gwayAnswer->addAnswer($answer4);
|
|
||||||
$question['idanswergood'] = $answerId1;
|
|
||||||
|
|
||||||
$question2 = $gateway->getQuestionByID($question['id']);
|
|
||||||
assertEquals($question['content'], $question2['content']);
|
|
||||||
assertEquals($lenght + 1, count($gateway->getQuestions()));
|
|
||||||
assertEquals($lenght2 + 1, count($gateway->getQuestionsByChapterAndDifficulty(1, 1)));
|
|
||||||
|
|
||||||
|
|
||||||
$question['content'] = "test Unit 2_";
|
|
||||||
$gateway->updateQuestion($question['id'], $question);
|
|
||||||
$question2 = $gateway->getQuestionByID($question['id']);
|
|
||||||
assertEquals($question['content'], $question2['content']);
|
|
||||||
|
|
||||||
$question['difficulty'] = 2;
|
|
||||||
$questionInstance = new Question(
|
|
||||||
$question['id'],
|
|
||||||
$question['content'],
|
|
||||||
$question['idchapter'],
|
|
||||||
$question['difficulty'],
|
|
||||||
$question['nbfails']
|
|
||||||
);
|
|
||||||
$questionInstance->setDifficulty($question['difficulty']);
|
|
||||||
$gateway->updateDifficulty($questionInstance);
|
|
||||||
$question3 = $gateway->getQuestionByID($question['id']);
|
|
||||||
assertEquals($question['difficulty'], $question3['difficulty']);
|
|
||||||
|
|
||||||
$question['nbfails'] = 1;
|
|
||||||
$questionInstance = new Question(
|
|
||||||
$question['id'],
|
|
||||||
$question['content'],
|
|
||||||
$question['idchapter'],
|
|
||||||
$question['difficulty'],
|
|
||||||
$question['nbfails']
|
|
||||||
);
|
|
||||||
$questionInstance->setNbFails($question['nbfails']);
|
|
||||||
$gateway->updateNbFails($questionInstance);
|
|
||||||
$question2 = $gateway->getQuestionByID($question['id']);
|
|
||||||
assertEquals($question['nbfails'], $question2['nbfails']);
|
|
||||||
|
|
||||||
|
|
||||||
$gateway->deleteQuestionByID($question['id']);
|
|
||||||
assertEquals($lenght, count($gateway->getQuestions()));
|
|
||||||
$gwayAnswer->deleteAnswer($answerId1);
|
|
||||||
$gwayAnswer->deleteAnswer($answerId2);
|
|
||||||
$gwayAnswer->deleteAnswer($answerId3);
|
|
||||||
$gwayAnswer->deleteAnswer($answerId4);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@ -1,47 +0,0 @@
|
|||||||
{
|
|
||||||
"active": true,
|
|
||||||
"name": "Instantiator",
|
|
||||||
"slug": "instantiator",
|
|
||||||
"docsSlug": "doctrine-instantiator",
|
|
||||||
"codePath": "/src",
|
|
||||||
"versions": [
|
|
||||||
{
|
|
||||||
"name": "1.5",
|
|
||||||
"branchName": "1.5.x",
|
|
||||||
"slug": "latest",
|
|
||||||
"upcoming": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "1.4",
|
|
||||||
"branchName": "1.4.x",
|
|
||||||
"slug": "1.4",
|
|
||||||
"aliases": [
|
|
||||||
"current",
|
|
||||||
"stable"
|
|
||||||
],
|
|
||||||
"maintained": true,
|
|
||||||
"current": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "1.3",
|
|
||||||
"branchName": "1.3.x",
|
|
||||||
"slug": "1.3",
|
|
||||||
"maintained": false
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "1.2",
|
|
||||||
"branchName": "1.2.x",
|
|
||||||
"slug": "1.2"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "1.1",
|
|
||||||
"branchName": "1.1.x",
|
|
||||||
"slug": "1.1"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "1.0",
|
|
||||||
"branchName": "1.0.x",
|
|
||||||
"slug": "1.0"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,35 +0,0 @@
|
|||||||
# Contributing
|
|
||||||
|
|
||||||
* Follow the [Doctrine Coding Standard](https://github.com/doctrine/coding-standard)
|
|
||||||
* The project will follow strict [object calisthenics](http://www.slideshare.net/guilhermeblanco/object-calisthenics-applied-to-php)
|
|
||||||
* Any contribution must provide tests for additional introduced conditions
|
|
||||||
* Any un-confirmed issue needs a failing test case before being accepted
|
|
||||||
* Pull requests must be sent from a new hotfix/feature branch, not from `master`.
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
To install the project and run the tests, you need to clone it first:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ git clone git://github.com/doctrine/instantiator.git
|
|
||||||
```
|
|
||||||
|
|
||||||
You will then need to run a composer installation:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ cd Instantiator
|
|
||||||
$ curl -s https://getcomposer.org/installer | php
|
|
||||||
$ php composer.phar update
|
|
||||||
```
|
|
||||||
|
|
||||||
## Testing
|
|
||||||
|
|
||||||
The PHPUnit version to be used is the one installed as a dev- dependency via composer:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
$ ./vendor/bin/phpunit
|
|
||||||
```
|
|
||||||
|
|
||||||
Accepted coverage for new contributions is 80%. Any contribution not satisfying this requirement
|
|
||||||
won't be merged.
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
|||||||
Copyright (c) 2014 Doctrine Project
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
||||||
this software and associated documentation files (the "Software"), to deal in
|
|
||||||
the Software without restriction, including without limitation the rights to
|
|
||||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
||||||
of the Software, and to permit persons to whom the Software is furnished to do
|
|
||||||
so, subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
||||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
||||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
||||||
SOFTWARE.
|
|
@ -1,38 +0,0 @@
|
|||||||
# Instantiator
|
|
||||||
|
|
||||||
This library provides a way of avoiding usage of constructors when instantiating PHP classes.
|
|
||||||
|
|
||||||
[](https://travis-ci.org/doctrine/instantiator)
|
|
||||||
[](https://codecov.io/gh/doctrine/instantiator/branch/master)
|
|
||||||
[](https://www.versioneye.com/package/php--doctrine--instantiator)
|
|
||||||
|
|
||||||
[](https://packagist.org/packages/doctrine/instantiator)
|
|
||||||
[](https://packagist.org/packages/doctrine/instantiator)
|
|
||||||
|
|
||||||
## Installation
|
|
||||||
|
|
||||||
The suggested installation method is via [composer](https://getcomposer.org/):
|
|
||||||
|
|
||||||
```sh
|
|
||||||
composer require doctrine/instantiator
|
|
||||||
```
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
The instantiator is able to create new instances of any class without using the constructor or any API of the class
|
|
||||||
itself:
|
|
||||||
|
|
||||||
```php
|
|
||||||
$instantiator = new \Doctrine\Instantiator\Instantiator();
|
|
||||||
|
|
||||||
$instance = $instantiator->instantiate(\My\ClassName\Here::class);
|
|
||||||
```
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
Please read the [CONTRIBUTING.md](CONTRIBUTING.md) contents if you wish to help out!
|
|
||||||
|
|
||||||
## Credits
|
|
||||||
|
|
||||||
This library was migrated from [ocramius/instantiator](https://github.com/Ocramius/Instantiator), which
|
|
||||||
has been donated to the doctrine organization, and which is now deprecated in favour of this package.
|
|
@ -1,48 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "doctrine/instantiator",
|
|
||||||
"description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
|
|
||||||
"type": "library",
|
|
||||||
"license": "MIT",
|
|
||||||
"homepage": "https://www.doctrine-project.org/projects/instantiator.html",
|
|
||||||
"keywords": [
|
|
||||||
"instantiate",
|
|
||||||
"constructor"
|
|
||||||
],
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Marco Pivetta",
|
|
||||||
"email": "ocramius@gmail.com",
|
|
||||||
"homepage": "https://ocramius.github.io/"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"require": {
|
|
||||||
"php": "^7.1 || ^8.0"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"ext-phar": "*",
|
|
||||||
"ext-pdo": "*",
|
|
||||||
"doctrine/coding-standard": "^9 || ^11",
|
|
||||||
"phpbench/phpbench": "^0.16 || ^1",
|
|
||||||
"phpstan/phpstan": "^1.4",
|
|
||||||
"phpstan/phpstan-phpunit": "^1",
|
|
||||||
"phpunit/phpunit": "^7.5 || ^8.5 || ^9.5",
|
|
||||||
"vimeo/psalm": "^4.30 || ^5.4"
|
|
||||||
},
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"Doctrine\\Instantiator\\": "src/Doctrine/Instantiator/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"autoload-dev": {
|
|
||||||
"psr-0": {
|
|
||||||
"DoctrineTest\\InstantiatorPerformance\\": "tests",
|
|
||||||
"DoctrineTest\\InstantiatorTest\\": "tests",
|
|
||||||
"DoctrineTest\\InstantiatorTestAsset\\": "tests"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"config": {
|
|
||||||
"allow-plugins": {
|
|
||||||
"dealerdirect/phpcodesniffer-composer-installer": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,4 +0,0 @@
|
|||||||
.. toctree::
|
|
||||||
:depth: 3
|
|
||||||
|
|
||||||
index
|
|
@ -1,16 +0,0 @@
|
|||||||
<?xml version="1.0"?>
|
|
||||||
<psalm
|
|
||||||
errorLevel="7"
|
|
||||||
phpVersion="8.2"
|
|
||||||
resolveFromConfigFile="true"
|
|
||||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
|
||||||
xmlns="https://getpsalm.org/schema/config"
|
|
||||||
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
|
|
||||||
>
|
|
||||||
<projectFiles>
|
|
||||||
<directory name="src" />
|
|
||||||
<ignoreFiles>
|
|
||||||
<directory name="vendor" />
|
|
||||||
</ignoreFiles>
|
|
||||||
</projectFiles>
|
|
||||||
</psalm>
|
|
@ -1,12 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Doctrine\Instantiator\Exception;
|
|
||||||
|
|
||||||
use Throwable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Base exception marker interface for the instantiator component
|
|
||||||
*/
|
|
||||||
interface ExceptionInterface extends Throwable
|
|
||||||
{
|
|
||||||
}
|
|
@ -1,50 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Doctrine\Instantiator\Exception;
|
|
||||||
|
|
||||||
use InvalidArgumentException as BaseInvalidArgumentException;
|
|
||||||
use ReflectionClass;
|
|
||||||
|
|
||||||
use function interface_exists;
|
|
||||||
use function sprintf;
|
|
||||||
use function trait_exists;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exception for invalid arguments provided to the instantiator
|
|
||||||
*/
|
|
||||||
class InvalidArgumentException extends BaseInvalidArgumentException implements ExceptionInterface
|
|
||||||
{
|
|
||||||
public static function fromNonExistingClass(string $className): self
|
|
||||||
{
|
|
||||||
if (interface_exists($className)) {
|
|
||||||
return new self(sprintf('The provided type "%s" is an interface, and cannot be instantiated', $className));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (trait_exists($className)) {
|
|
||||||
return new self(sprintf('The provided type "%s" is a trait, and cannot be instantiated', $className));
|
|
||||||
}
|
|
||||||
|
|
||||||
return new self(sprintf('The provided class "%s" does not exist', $className));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @phpstan-param ReflectionClass<T> $reflectionClass
|
|
||||||
*
|
|
||||||
* @template T of object
|
|
||||||
*/
|
|
||||||
public static function fromAbstractClass(ReflectionClass $reflectionClass): self
|
|
||||||
{
|
|
||||||
return new self(sprintf(
|
|
||||||
'The provided class "%s" is abstract, and cannot be instantiated',
|
|
||||||
$reflectionClass->getName()
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function fromEnum(string $className): self
|
|
||||||
{
|
|
||||||
return new self(sprintf(
|
|
||||||
'The provided class "%s" is an enum, and cannot be instantiated',
|
|
||||||
$className
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,59 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Doctrine\Instantiator\Exception;
|
|
||||||
|
|
||||||
use Exception;
|
|
||||||
use ReflectionClass;
|
|
||||||
use UnexpectedValueException as BaseUnexpectedValueException;
|
|
||||||
|
|
||||||
use function sprintf;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Exception for given parameters causing invalid/unexpected state on instantiation
|
|
||||||
*/
|
|
||||||
class UnexpectedValueException extends BaseUnexpectedValueException implements ExceptionInterface
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @phpstan-param ReflectionClass<T> $reflectionClass
|
|
||||||
*
|
|
||||||
* @template T of object
|
|
||||||
*/
|
|
||||||
public static function fromSerializationTriggeredException(
|
|
||||||
ReflectionClass $reflectionClass,
|
|
||||||
Exception $exception
|
|
||||||
): self {
|
|
||||||
return new self(
|
|
||||||
sprintf(
|
|
||||||
'An exception was raised while trying to instantiate an instance of "%s" via un-serialization',
|
|
||||||
$reflectionClass->getName()
|
|
||||||
),
|
|
||||||
0,
|
|
||||||
$exception
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @phpstan-param ReflectionClass<T> $reflectionClass
|
|
||||||
*
|
|
||||||
* @template T of object
|
|
||||||
*/
|
|
||||||
public static function fromUncleanUnSerialization(
|
|
||||||
ReflectionClass $reflectionClass,
|
|
||||||
string $errorString,
|
|
||||||
int $errorCode,
|
|
||||||
string $errorFile,
|
|
||||||
int $errorLine
|
|
||||||
): self {
|
|
||||||
return new self(
|
|
||||||
sprintf(
|
|
||||||
'Could not produce an instance of "%s" via un-serialization, since an error was triggered '
|
|
||||||
. 'in file "%s" at line "%d"',
|
|
||||||
$reflectionClass->getName(),
|
|
||||||
$errorFile,
|
|
||||||
$errorLine
|
|
||||||
),
|
|
||||||
0,
|
|
||||||
new Exception($errorString, $errorCode)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,262 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Doctrine\Instantiator;
|
|
||||||
|
|
||||||
use ArrayIterator;
|
|
||||||
use Doctrine\Instantiator\Exception\ExceptionInterface;
|
|
||||||
use Doctrine\Instantiator\Exception\InvalidArgumentException;
|
|
||||||
use Doctrine\Instantiator\Exception\UnexpectedValueException;
|
|
||||||
use Exception;
|
|
||||||
use ReflectionClass;
|
|
||||||
use ReflectionException;
|
|
||||||
use Serializable;
|
|
||||||
|
|
||||||
use function class_exists;
|
|
||||||
use function enum_exists;
|
|
||||||
use function is_subclass_of;
|
|
||||||
use function restore_error_handler;
|
|
||||||
use function set_error_handler;
|
|
||||||
use function sprintf;
|
|
||||||
use function strlen;
|
|
||||||
use function unserialize;
|
|
||||||
|
|
||||||
use const PHP_VERSION_ID;
|
|
||||||
|
|
||||||
final class Instantiator implements InstantiatorInterface
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Markers used internally by PHP to define whether {@see \unserialize} should invoke
|
|
||||||
* the method {@see \Serializable::unserialize()} when dealing with classes implementing
|
|
||||||
* the {@see \Serializable} interface.
|
|
||||||
*
|
|
||||||
* @deprecated This constant will be private in 2.0
|
|
||||||
*/
|
|
||||||
public const SERIALIZATION_FORMAT_USE_UNSERIALIZER = 'C';
|
|
||||||
|
|
||||||
/** @deprecated This constant will be private in 2.0 */
|
|
||||||
public const SERIALIZATION_FORMAT_AVOID_UNSERIALIZER = 'O';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Used to instantiate specific classes, indexed by class name.
|
|
||||||
*
|
|
||||||
* @var callable[]
|
|
||||||
*/
|
|
||||||
private static $cachedInstantiators = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Array of objects that can directly be cloned, indexed by class name.
|
|
||||||
*
|
|
||||||
* @var object[]
|
|
||||||
*/
|
|
||||||
private static $cachedCloneables = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $className
|
|
||||||
* @phpstan-param class-string<T> $className
|
|
||||||
*
|
|
||||||
* @return object
|
|
||||||
* @phpstan-return T
|
|
||||||
*
|
|
||||||
* @throws ExceptionInterface
|
|
||||||
*
|
|
||||||
* @template T of object
|
|
||||||
*/
|
|
||||||
public function instantiate($className)
|
|
||||||
{
|
|
||||||
if (isset(self::$cachedCloneables[$className])) {
|
|
||||||
/** @phpstan-var T */
|
|
||||||
$cachedCloneable = self::$cachedCloneables[$className];
|
|
||||||
|
|
||||||
return clone $cachedCloneable;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isset(self::$cachedInstantiators[$className])) {
|
|
||||||
$factory = self::$cachedInstantiators[$className];
|
|
||||||
|
|
||||||
return $factory();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->buildAndCacheFromFactory($className);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds the requested object and caches it in static properties for performance
|
|
||||||
*
|
|
||||||
* @phpstan-param class-string<T> $className
|
|
||||||
*
|
|
||||||
* @return object
|
|
||||||
* @phpstan-return T
|
|
||||||
*
|
|
||||||
* @template T of object
|
|
||||||
*/
|
|
||||||
private function buildAndCacheFromFactory(string $className)
|
|
||||||
{
|
|
||||||
$factory = self::$cachedInstantiators[$className] = $this->buildFactory($className);
|
|
||||||
$instance = $factory();
|
|
||||||
|
|
||||||
if ($this->isSafeToClone(new ReflectionClass($instance))) {
|
|
||||||
self::$cachedCloneables[$className] = clone $instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Builds a callable capable of instantiating the given $className without
|
|
||||||
* invoking its constructor.
|
|
||||||
*
|
|
||||||
* @phpstan-param class-string<T> $className
|
|
||||||
*
|
|
||||||
* @phpstan-return callable(): T
|
|
||||||
*
|
|
||||||
* @throws InvalidArgumentException
|
|
||||||
* @throws UnexpectedValueException
|
|
||||||
* @throws ReflectionException
|
|
||||||
*
|
|
||||||
* @template T of object
|
|
||||||
*/
|
|
||||||
private function buildFactory(string $className): callable
|
|
||||||
{
|
|
||||||
$reflectionClass = $this->getReflectionClass($className);
|
|
||||||
|
|
||||||
if ($this->isInstantiableViaReflection($reflectionClass)) {
|
|
||||||
return [$reflectionClass, 'newInstanceWithoutConstructor'];
|
|
||||||
}
|
|
||||||
|
|
||||||
$serializedString = sprintf(
|
|
||||||
'%s:%d:"%s":0:{}',
|
|
||||||
is_subclass_of($className, Serializable::class) ? self::SERIALIZATION_FORMAT_USE_UNSERIALIZER : self::SERIALIZATION_FORMAT_AVOID_UNSERIALIZER,
|
|
||||||
strlen($className),
|
|
||||||
$className
|
|
||||||
);
|
|
||||||
|
|
||||||
$this->checkIfUnSerializationIsSupported($reflectionClass, $serializedString);
|
|
||||||
|
|
||||||
return static function () use ($serializedString) {
|
|
||||||
return unserialize($serializedString);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @phpstan-param class-string<T> $className
|
|
||||||
*
|
|
||||||
* @phpstan-return ReflectionClass<T>
|
|
||||||
*
|
|
||||||
* @throws InvalidArgumentException
|
|
||||||
* @throws ReflectionException
|
|
||||||
*
|
|
||||||
* @template T of object
|
|
||||||
*/
|
|
||||||
private function getReflectionClass(string $className): ReflectionClass
|
|
||||||
{
|
|
||||||
if (! class_exists($className)) {
|
|
||||||
throw InvalidArgumentException::fromNonExistingClass($className);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PHP_VERSION_ID >= 80100 && enum_exists($className, false)) {
|
|
||||||
throw InvalidArgumentException::fromEnum($className);
|
|
||||||
}
|
|
||||||
|
|
||||||
$reflection = new ReflectionClass($className);
|
|
||||||
|
|
||||||
if ($reflection->isAbstract()) {
|
|
||||||
throw InvalidArgumentException::fromAbstractClass($reflection);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $reflection;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @phpstan-param ReflectionClass<T> $reflectionClass
|
|
||||||
*
|
|
||||||
* @throws UnexpectedValueException
|
|
||||||
*
|
|
||||||
* @template T of object
|
|
||||||
*/
|
|
||||||
private function checkIfUnSerializationIsSupported(ReflectionClass $reflectionClass, string $serializedString): void
|
|
||||||
{
|
|
||||||
set_error_handler(static function (int $code, string $message, string $file, int $line) use ($reflectionClass, &$error): bool {
|
|
||||||
$error = UnexpectedValueException::fromUncleanUnSerialization(
|
|
||||||
$reflectionClass,
|
|
||||||
$message,
|
|
||||||
$code,
|
|
||||||
$file,
|
|
||||||
$line
|
|
||||||
);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
|
||||||
$this->attemptInstantiationViaUnSerialization($reflectionClass, $serializedString);
|
|
||||||
} finally {
|
|
||||||
restore_error_handler();
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($error) {
|
|
||||||
throw $error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @phpstan-param ReflectionClass<T> $reflectionClass
|
|
||||||
*
|
|
||||||
* @throws UnexpectedValueException
|
|
||||||
*
|
|
||||||
* @template T of object
|
|
||||||
*/
|
|
||||||
private function attemptInstantiationViaUnSerialization(ReflectionClass $reflectionClass, string $serializedString): void
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
unserialize($serializedString);
|
|
||||||
} catch (Exception $exception) {
|
|
||||||
throw UnexpectedValueException::fromSerializationTriggeredException($reflectionClass, $exception);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @phpstan-param ReflectionClass<T> $reflectionClass
|
|
||||||
*
|
|
||||||
* @template T of object
|
|
||||||
*/
|
|
||||||
private function isInstantiableViaReflection(ReflectionClass $reflectionClass): bool
|
|
||||||
{
|
|
||||||
return ! ($this->hasInternalAncestors($reflectionClass) && $reflectionClass->isFinal());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Verifies whether the given class is to be considered internal
|
|
||||||
*
|
|
||||||
* @phpstan-param ReflectionClass<T> $reflectionClass
|
|
||||||
*
|
|
||||||
* @template T of object
|
|
||||||
*/
|
|
||||||
private function hasInternalAncestors(ReflectionClass $reflectionClass): bool
|
|
||||||
{
|
|
||||||
do {
|
|
||||||
if ($reflectionClass->isInternal()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
$reflectionClass = $reflectionClass->getParentClass();
|
|
||||||
} while ($reflectionClass);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Checks if a class is cloneable
|
|
||||||
*
|
|
||||||
* Classes implementing `__clone` cannot be safely cloned, as that may cause side-effects.
|
|
||||||
*
|
|
||||||
* @phpstan-param ReflectionClass<T> $reflectionClass
|
|
||||||
*
|
|
||||||
* @template T of object
|
|
||||||
*/
|
|
||||||
private function isSafeToClone(ReflectionClass $reflectionClass): bool
|
|
||||||
{
|
|
||||||
return $reflectionClass->isCloneable()
|
|
||||||
&& ! $reflectionClass->hasMethod('__clone')
|
|
||||||
&& ! $reflectionClass->isSubclassOf(ArrayIterator::class);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace Doctrine\Instantiator;
|
|
||||||
|
|
||||||
use Doctrine\Instantiator\Exception\ExceptionInterface;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Instantiator provides utility methods to build objects without invoking their constructors
|
|
||||||
*/
|
|
||||||
interface InstantiatorInterface
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @param string $className
|
|
||||||
* @phpstan-param class-string<T> $className
|
|
||||||
*
|
|
||||||
* @return object
|
|
||||||
* @phpstan-return T
|
|
||||||
*
|
|
||||||
* @throws ExceptionInterface
|
|
||||||
*
|
|
||||||
* @template T of object
|
|
||||||
*/
|
|
||||||
public function instantiate($className);
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
# These are supported funding model platforms
|
|
||||||
|
|
||||||
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
|
||||||
patreon: # Replace with a single Patreon username
|
|
||||||
open_collective: # Replace with a single Open Collective username
|
|
||||||
ko_fi: # Replace with a single Ko-fi username
|
|
||||||
tidelift: "packagist/myclabs/deep-copy"
|
|
||||||
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
|
||||||
liberapay: # Replace with a single Liberapay username
|
|
||||||
issuehunt: # Replace with a single IssueHunt username
|
|
||||||
otechie: # Replace with a single Otechie username
|
|
||||||
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
|
@ -1,101 +0,0 @@
|
|||||||
name: "Continuous Integration"
|
|
||||||
|
|
||||||
on:
|
|
||||||
- pull_request
|
|
||||||
- push
|
|
||||||
|
|
||||||
env:
|
|
||||||
COMPOSER_ROOT_VERSION: 1.99
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
composer-json-lint:
|
|
||||||
name: "Lint composer.json"
|
|
||||||
|
|
||||||
runs-on: "ubuntu-latest"
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
php-version:
|
|
||||||
- "8.1"
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: "Checkout"
|
|
||||||
uses: "actions/checkout@v2"
|
|
||||||
|
|
||||||
- name: "Install PHP"
|
|
||||||
uses: "shivammathur/setup-php@v2"
|
|
||||||
with:
|
|
||||||
coverage: "none"
|
|
||||||
php-version: "${{ matrix.php-version }}"
|
|
||||||
tools: composer-normalize
|
|
||||||
|
|
||||||
- name: "Get composer cache directory"
|
|
||||||
id: composercache
|
|
||||||
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
|
|
||||||
|
|
||||||
- name: "Cache dependencies"
|
|
||||||
uses: actions/cache@v2
|
|
||||||
with:
|
|
||||||
path: ${{ steps.composercache.outputs.dir }}
|
|
||||||
key: ${{ runner.os }}-php-${{ matrix.php-version }}-${{ matrix.dependencies }}-composer-${{ hashFiles('**/composer.json') }}
|
|
||||||
restore-keys: ${{ runner.os }}-php-${{ matrix.php-version }}-${{ matrix.dependencies }}-composer-
|
|
||||||
|
|
||||||
- name: "Install dependencies"
|
|
||||||
run: "composer update --no-interaction --no-progress"
|
|
||||||
|
|
||||||
- name: "Validate composer.json"
|
|
||||||
run: "composer validate --strict"
|
|
||||||
|
|
||||||
- name: "Normalize composer.json"
|
|
||||||
run: "composer-normalize --dry-run"
|
|
||||||
|
|
||||||
tests:
|
|
||||||
name: "Tests"
|
|
||||||
|
|
||||||
runs-on: "ubuntu-latest"
|
|
||||||
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
php-version:
|
|
||||||
- "7.1"
|
|
||||||
- "7.2"
|
|
||||||
- "7.3"
|
|
||||||
- "7.4"
|
|
||||||
- "8.0"
|
|
||||||
- "8.1"
|
|
||||||
dependencies:
|
|
||||||
- "lowest"
|
|
||||||
- "highest"
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: "Checkout"
|
|
||||||
uses: "actions/checkout@v2"
|
|
||||||
|
|
||||||
- name: "Install PHP"
|
|
||||||
uses: "shivammathur/setup-php@v2"
|
|
||||||
with:
|
|
||||||
php-version: "${{ matrix.php-version }}"
|
|
||||||
ini-values: zend.assertions=1
|
|
||||||
|
|
||||||
- name: "Get composer cache directory"
|
|
||||||
id: composercache
|
|
||||||
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
|
|
||||||
|
|
||||||
- name: "Cache dependencies"
|
|
||||||
uses: actions/cache@v2
|
|
||||||
with:
|
|
||||||
path: ${{ steps.composercache.outputs.dir }}
|
|
||||||
key: ${{ runner.os }}-php-${{ matrix.php-version }}-${{ matrix.dependencies }}-composer-${{ hashFiles('**/composer.json') }}
|
|
||||||
restore-keys: ${{ runner.os }}-php-${{ matrix.php-version }}-${{ matrix.dependencies }}-composer-
|
|
||||||
|
|
||||||
- name: "Install lowest dependencies"
|
|
||||||
if: ${{ matrix.dependencies == 'lowest' }}
|
|
||||||
run: "composer update --no-interaction --no-progress --prefer-lowest"
|
|
||||||
|
|
||||||
- name: "Install highest dependencies"
|
|
||||||
if: ${{ matrix.dependencies == 'highest' }}
|
|
||||||
run: "composer update --no-interaction --no-progress"
|
|
||||||
|
|
||||||
- name: "Run tests"
|
|
||||||
timeout-minutes: 3
|
|
||||||
run: "vendor/bin/phpunit"
|
|
@ -1,20 +0,0 @@
|
|||||||
The MIT License (MIT)
|
|
||||||
|
|
||||||
Copyright (c) 2013 My C-Sense
|
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
||||||
this software and associated documentation files (the "Software"), to deal in
|
|
||||||
the Software without restriction, including without limitation the rights to
|
|
||||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
||||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
||||||
subject to the following conditions:
|
|
||||||
|
|
||||||
The above copyright notice and this permission notice shall be included in all
|
|
||||||
copies or substantial portions of the Software.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
||||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
||||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
||||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -1,406 +0,0 @@
|
|||||||
# DeepCopy
|
|
||||||
|
|
||||||
DeepCopy helps you create deep copies (clones) of your objects. It is designed to handle cycles in the association graph.
|
|
||||||
|
|
||||||
[](https://packagist.org/packages/myclabs/deep-copy)
|
|
||||||
[](https://github.com/myclabs/DeepCopy/actions)
|
|
||||||
|
|
||||||
## Table of Contents
|
|
||||||
|
|
||||||
1. [How](#how)
|
|
||||||
1. [Why](#why)
|
|
||||||
1. [Using simply `clone`](#using-simply-clone)
|
|
||||||
1. [Overriding `__clone()`](#overriding-__clone)
|
|
||||||
1. [With `DeepCopy`](#with-deepcopy)
|
|
||||||
1. [How it works](#how-it-works)
|
|
||||||
1. [Going further](#going-further)
|
|
||||||
1. [Matchers](#matchers)
|
|
||||||
1. [Property name](#property-name)
|
|
||||||
1. [Specific property](#specific-property)
|
|
||||||
1. [Type](#type)
|
|
||||||
1. [Filters](#filters)
|
|
||||||
1. [`SetNullFilter`](#setnullfilter-filter)
|
|
||||||
1. [`KeepFilter`](#keepfilter-filter)
|
|
||||||
1. [`DoctrineCollectionFilter`](#doctrinecollectionfilter-filter)
|
|
||||||
1. [`DoctrineEmptyCollectionFilter`](#doctrineemptycollectionfilter-filter)
|
|
||||||
1. [`DoctrineProxyFilter`](#doctrineproxyfilter-filter)
|
|
||||||
1. [`ReplaceFilter`](#replacefilter-type-filter)
|
|
||||||
1. [`ShallowCopyFilter`](#shallowcopyfilter-type-filter)
|
|
||||||
1. [Edge cases](#edge-cases)
|
|
||||||
1. [Contributing](#contributing)
|
|
||||||
1. [Tests](#tests)
|
|
||||||
|
|
||||||
|
|
||||||
## How?
|
|
||||||
|
|
||||||
Install with Composer:
|
|
||||||
|
|
||||||
```
|
|
||||||
composer require myclabs/deep-copy
|
|
||||||
```
|
|
||||||
|
|
||||||
Use it:
|
|
||||||
|
|
||||||
```php
|
|
||||||
use DeepCopy\DeepCopy;
|
|
||||||
|
|
||||||
$copier = new DeepCopy();
|
|
||||||
$myCopy = $copier->copy($myObject);
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Why?
|
|
||||||
|
|
||||||
- How do you create copies of your objects?
|
|
||||||
|
|
||||||
```php
|
|
||||||
$myCopy = clone $myObject;
|
|
||||||
```
|
|
||||||
|
|
||||||
- How do you create **deep** copies of your objects (i.e. copying also all the objects referenced in the properties)?
|
|
||||||
|
|
||||||
You use [`__clone()`](http://www.php.net/manual/en/language.oop5.cloning.php#object.clone) and implement the behavior
|
|
||||||
yourself.
|
|
||||||
|
|
||||||
- But how do you handle **cycles** in the association graph?
|
|
||||||
|
|
||||||
Now you're in for a big mess :(
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
### Using simply `clone`
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
### Overriding `__clone()`
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
### With `DeepCopy`
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
## How it works
|
|
||||||
|
|
||||||
DeepCopy recursively traverses all the object's properties and clones them. To avoid cloning the same object twice it
|
|
||||||
keeps a hash map of all instances and thus preserves the object graph.
|
|
||||||
|
|
||||||
To use it:
|
|
||||||
|
|
||||||
```php
|
|
||||||
use function DeepCopy\deep_copy;
|
|
||||||
|
|
||||||
$copy = deep_copy($var);
|
|
||||||
```
|
|
||||||
|
|
||||||
Alternatively, you can create your own `DeepCopy` instance to configure it differently for example:
|
|
||||||
|
|
||||||
```php
|
|
||||||
use DeepCopy\DeepCopy;
|
|
||||||
|
|
||||||
$copier = new DeepCopy(true);
|
|
||||||
|
|
||||||
$copy = $copier->copy($var);
|
|
||||||
```
|
|
||||||
|
|
||||||
You may want to roll your own deep copy function:
|
|
||||||
|
|
||||||
```php
|
|
||||||
namespace Acme;
|
|
||||||
|
|
||||||
use DeepCopy\DeepCopy;
|
|
||||||
|
|
||||||
function deep_copy($var)
|
|
||||||
{
|
|
||||||
static $copier = null;
|
|
||||||
|
|
||||||
if (null === $copier) {
|
|
||||||
$copier = new DeepCopy(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $copier->copy($var);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Going further
|
|
||||||
|
|
||||||
You can add filters to customize the copy process.
|
|
||||||
|
|
||||||
The method to add a filter is `DeepCopy\DeepCopy::addFilter($filter, $matcher)`,
|
|
||||||
with `$filter` implementing `DeepCopy\Filter\Filter`
|
|
||||||
and `$matcher` implementing `DeepCopy\Matcher\Matcher`.
|
|
||||||
|
|
||||||
We provide some generic filters and matchers.
|
|
||||||
|
|
||||||
|
|
||||||
### Matchers
|
|
||||||
|
|
||||||
- `DeepCopy\Matcher` applies on a object attribute.
|
|
||||||
- `DeepCopy\TypeMatcher` applies on any element found in graph, including array elements.
|
|
||||||
|
|
||||||
|
|
||||||
#### Property name
|
|
||||||
|
|
||||||
The `PropertyNameMatcher` will match a property by its name:
|
|
||||||
|
|
||||||
```php
|
|
||||||
use DeepCopy\Matcher\PropertyNameMatcher;
|
|
||||||
|
|
||||||
// Will apply a filter to any property of any objects named "id"
|
|
||||||
$matcher = new PropertyNameMatcher('id');
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
#### Specific property
|
|
||||||
|
|
||||||
The `PropertyMatcher` will match a specific property of a specific class:
|
|
||||||
|
|
||||||
```php
|
|
||||||
use DeepCopy\Matcher\PropertyMatcher;
|
|
||||||
|
|
||||||
// Will apply a filter to the property "id" of any objects of the class "MyClass"
|
|
||||||
$matcher = new PropertyMatcher('MyClass', 'id');
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
#### Type
|
|
||||||
|
|
||||||
The `TypeMatcher` will match any element by its type (instance of a class or any value that could be parameter of
|
|
||||||
[gettype()](http://php.net/manual/en/function.gettype.php) function):
|
|
||||||
|
|
||||||
```php
|
|
||||||
use DeepCopy\TypeMatcher\TypeMatcher;
|
|
||||||
|
|
||||||
// Will apply a filter to any object that is an instance of Doctrine\Common\Collections\Collection
|
|
||||||
$matcher = new TypeMatcher('Doctrine\Common\Collections\Collection');
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
### Filters
|
|
||||||
|
|
||||||
- `DeepCopy\Filter` applies a transformation to the object attribute matched by `DeepCopy\Matcher`
|
|
||||||
- `DeepCopy\TypeFilter` applies a transformation to any element matched by `DeepCopy\TypeMatcher`
|
|
||||||
|
|
||||||
By design, matching a filter will stop the chain of filters (i.e. the next ones will not be applied).
|
|
||||||
Using the ([`ChainableFilter`](#chainablefilter-filter)) won't stop the chain of filters.
|
|
||||||
|
|
||||||
|
|
||||||
#### `SetNullFilter` (filter)
|
|
||||||
|
|
||||||
Let's say for example that you are copying a database record (or a Doctrine entity), so you want the copy not to have
|
|
||||||
any ID:
|
|
||||||
|
|
||||||
```php
|
|
||||||
use DeepCopy\DeepCopy;
|
|
||||||
use DeepCopy\Filter\SetNullFilter;
|
|
||||||
use DeepCopy\Matcher\PropertyNameMatcher;
|
|
||||||
|
|
||||||
$object = MyClass::load(123);
|
|
||||||
echo $object->id; // 123
|
|
||||||
|
|
||||||
$copier = new DeepCopy();
|
|
||||||
$copier->addFilter(new SetNullFilter(), new PropertyNameMatcher('id'));
|
|
||||||
|
|
||||||
$copy = $copier->copy($object);
|
|
||||||
|
|
||||||
echo $copy->id; // null
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
#### `KeepFilter` (filter)
|
|
||||||
|
|
||||||
If you want a property to remain untouched (for example, an association to an object):
|
|
||||||
|
|
||||||
```php
|
|
||||||
use DeepCopy\DeepCopy;
|
|
||||||
use DeepCopy\Filter\KeepFilter;
|
|
||||||
use DeepCopy\Matcher\PropertyMatcher;
|
|
||||||
|
|
||||||
$copier = new DeepCopy();
|
|
||||||
$copier->addFilter(new KeepFilter(), new PropertyMatcher('MyClass', 'category'));
|
|
||||||
|
|
||||||
$copy = $copier->copy($object);
|
|
||||||
// $copy->category has not been touched
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
#### `ChainableFilter` (filter)
|
|
||||||
|
|
||||||
If you use cloning on proxy classes, you might want to apply two filters for:
|
|
||||||
1. loading the data
|
|
||||||
2. applying a transformation
|
|
||||||
|
|
||||||
You can use the `ChainableFilter` as a decorator of the proxy loader filter, which won't stop the chain of filters (i.e.
|
|
||||||
the next ones may be applied).
|
|
||||||
|
|
||||||
|
|
||||||
```php
|
|
||||||
use DeepCopy\DeepCopy;
|
|
||||||
use DeepCopy\Filter\ChainableFilter;
|
|
||||||
use DeepCopy\Filter\Doctrine\DoctrineProxyFilter;
|
|
||||||
use DeepCopy\Filter\SetNullFilter;
|
|
||||||
use DeepCopy\Matcher\Doctrine\DoctrineProxyMatcher;
|
|
||||||
use DeepCopy\Matcher\PropertyNameMatcher;
|
|
||||||
|
|
||||||
$copier = new DeepCopy();
|
|
||||||
$copier->addFilter(new ChainableFilter(new DoctrineProxyFilter()), new DoctrineProxyMatcher());
|
|
||||||
$copier->addFilter(new SetNullFilter(), new PropertyNameMatcher('id'));
|
|
||||||
|
|
||||||
$copy = $copier->copy($object);
|
|
||||||
|
|
||||||
echo $copy->id; // null
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
#### `DoctrineCollectionFilter` (filter)
|
|
||||||
|
|
||||||
If you use Doctrine and want to copy an entity, you will need to use the `DoctrineCollectionFilter`:
|
|
||||||
|
|
||||||
```php
|
|
||||||
use DeepCopy\DeepCopy;
|
|
||||||
use DeepCopy\Filter\Doctrine\DoctrineCollectionFilter;
|
|
||||||
use DeepCopy\Matcher\PropertyTypeMatcher;
|
|
||||||
|
|
||||||
$copier = new DeepCopy();
|
|
||||||
$copier->addFilter(new DoctrineCollectionFilter(), new PropertyTypeMatcher('Doctrine\Common\Collections\Collection'));
|
|
||||||
|
|
||||||
$copy = $copier->copy($object);
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
#### `DoctrineEmptyCollectionFilter` (filter)
|
|
||||||
|
|
||||||
If you use Doctrine and want to copy an entity who contains a `Collection` that you want to be reset, you can use the
|
|
||||||
`DoctrineEmptyCollectionFilter`
|
|
||||||
|
|
||||||
```php
|
|
||||||
use DeepCopy\DeepCopy;
|
|
||||||
use DeepCopy\Filter\Doctrine\DoctrineEmptyCollectionFilter;
|
|
||||||
use DeepCopy\Matcher\PropertyMatcher;
|
|
||||||
|
|
||||||
$copier = new DeepCopy();
|
|
||||||
$copier->addFilter(new DoctrineEmptyCollectionFilter(), new PropertyMatcher('MyClass', 'myProperty'));
|
|
||||||
|
|
||||||
$copy = $copier->copy($object);
|
|
||||||
|
|
||||||
// $copy->myProperty will return an empty collection
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
#### `DoctrineProxyFilter` (filter)
|
|
||||||
|
|
||||||
If you use Doctrine and use cloning on lazy loaded entities, you might encounter errors mentioning missing fields on a
|
|
||||||
Doctrine proxy class (...\\\_\_CG\_\_\Proxy).
|
|
||||||
You can use the `DoctrineProxyFilter` to load the actual entity behind the Doctrine proxy class.
|
|
||||||
**Make sure, though, to put this as one of your very first filters in the filter chain so that the entity is loaded
|
|
||||||
before other filters are applied!**
|
|
||||||
We recommend to decorate the `DoctrineProxyFilter` with the `ChainableFilter` to allow applying other filters to the
|
|
||||||
cloned lazy loaded entities.
|
|
||||||
|
|
||||||
```php
|
|
||||||
use DeepCopy\DeepCopy;
|
|
||||||
use DeepCopy\Filter\Doctrine\DoctrineProxyFilter;
|
|
||||||
use DeepCopy\Matcher\Doctrine\DoctrineProxyMatcher;
|
|
||||||
|
|
||||||
$copier = new DeepCopy();
|
|
||||||
$copier->addFilter(new ChainableFilter(new DoctrineProxyFilter()), new DoctrineProxyMatcher());
|
|
||||||
|
|
||||||
$copy = $copier->copy($object);
|
|
||||||
|
|
||||||
// $copy should now contain a clone of all entities, including those that were not yet fully loaded.
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
#### `ReplaceFilter` (type filter)
|
|
||||||
|
|
||||||
1. If you want to replace the value of a property:
|
|
||||||
|
|
||||||
```php
|
|
||||||
use DeepCopy\DeepCopy;
|
|
||||||
use DeepCopy\Filter\ReplaceFilter;
|
|
||||||
use DeepCopy\Matcher\PropertyMatcher;
|
|
||||||
|
|
||||||
$copier = new DeepCopy();
|
|
||||||
$callback = function ($currentValue) {
|
|
||||||
return $currentValue . ' (copy)'
|
|
||||||
};
|
|
||||||
$copier->addFilter(new ReplaceFilter($callback), new PropertyMatcher('MyClass', 'title'));
|
|
||||||
|
|
||||||
$copy = $copier->copy($object);
|
|
||||||
|
|
||||||
// $copy->title will contain the data returned by the callback, e.g. 'The title (copy)'
|
|
||||||
```
|
|
||||||
|
|
||||||
2. If you want to replace whole element:
|
|
||||||
|
|
||||||
```php
|
|
||||||
use DeepCopy\DeepCopy;
|
|
||||||
use DeepCopy\TypeFilter\ReplaceFilter;
|
|
||||||
use DeepCopy\TypeMatcher\TypeMatcher;
|
|
||||||
|
|
||||||
$copier = new DeepCopy();
|
|
||||||
$callback = function (MyClass $myClass) {
|
|
||||||
return get_class($myClass);
|
|
||||||
};
|
|
||||||
$copier->addTypeFilter(new ReplaceFilter($callback), new TypeMatcher('MyClass'));
|
|
||||||
|
|
||||||
$copy = $copier->copy([new MyClass, 'some string', new MyClass]);
|
|
||||||
|
|
||||||
// $copy will contain ['MyClass', 'some string', 'MyClass']
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
The `$callback` parameter of the `ReplaceFilter` constructor accepts any PHP callable.
|
|
||||||
|
|
||||||
|
|
||||||
#### `ShallowCopyFilter` (type filter)
|
|
||||||
|
|
||||||
Stop *DeepCopy* from recursively copying element, using standard `clone` instead:
|
|
||||||
|
|
||||||
```php
|
|
||||||
use DeepCopy\DeepCopy;
|
|
||||||
use DeepCopy\TypeFilter\ShallowCopyFilter;
|
|
||||||
use DeepCopy\TypeMatcher\TypeMatcher;
|
|
||||||
use Mockery as m;
|
|
||||||
|
|
||||||
$this->deepCopy = new DeepCopy();
|
|
||||||
$this->deepCopy->addTypeFilter(
|
|
||||||
new ShallowCopyFilter,
|
|
||||||
new TypeMatcher(m\MockInterface::class)
|
|
||||||
);
|
|
||||||
|
|
||||||
$myServiceWithMocks = new MyService(m::mock(MyDependency1::class), m::mock(MyDependency2::class));
|
|
||||||
// All mocks will be just cloned, not deep copied
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
## Edge cases
|
|
||||||
|
|
||||||
The following structures cannot be deep-copied with PHP Reflection. As a result they are shallow cloned and filters are
|
|
||||||
not applied. There is two ways for you to handle them:
|
|
||||||
|
|
||||||
- Implement your own `__clone()` method
|
|
||||||
- Use a filter with a type matcher
|
|
||||||
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
DeepCopy is distributed under the MIT license.
|
|
||||||
|
|
||||||
|
|
||||||
### Tests
|
|
||||||
|
|
||||||
Running the tests is simple:
|
|
||||||
|
|
||||||
```php
|
|
||||||
vendor/bin/phpunit
|
|
||||||
```
|
|
||||||
|
|
||||||
### Support
|
|
||||||
|
|
||||||
Get professional support via [the Tidelift Subscription](https://tidelift.com/subscription/pkg/packagist-myclabs-deep-copy?utm_source=packagist-myclabs-deep-copy&utm_medium=referral&utm_campaign=readme).
|
|
@ -1,42 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "myclabs/deep-copy",
|
|
||||||
"description": "Create deep copies (clones) of your objects",
|
|
||||||
"license": "MIT",
|
|
||||||
"type": "library",
|
|
||||||
"keywords": [
|
|
||||||
"clone",
|
|
||||||
"copy",
|
|
||||||
"duplicate",
|
|
||||||
"object",
|
|
||||||
"object graph"
|
|
||||||
],
|
|
||||||
"require": {
|
|
||||||
"php": "^7.1 || ^8.0"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"doctrine/collections": "^1.6.8",
|
|
||||||
"doctrine/common": "^2.13.3 || ^3.2.2",
|
|
||||||
"phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13"
|
|
||||||
},
|
|
||||||
"conflict": {
|
|
||||||
"doctrine/collections": "<1.6.8",
|
|
||||||
"doctrine/common": "<2.13.3 || >=3,<3.2.2"
|
|
||||||
},
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"DeepCopy\\": "src/DeepCopy/"
|
|
||||||
},
|
|
||||||
"files": [
|
|
||||||
"src/DeepCopy/deep_copy.php"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"autoload-dev": {
|
|
||||||
"psr-4": {
|
|
||||||
"DeepCopy\\": "fixtures/",
|
|
||||||
"DeepCopyTest\\": "tests/DeepCopyTest/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"config": {
|
|
||||||
"sort-packages": true
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,308 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace DeepCopy;
|
|
||||||
|
|
||||||
use ArrayObject;
|
|
||||||
use DateInterval;
|
|
||||||
use DateTimeInterface;
|
|
||||||
use DateTimeZone;
|
|
||||||
use DeepCopy\Exception\CloneException;
|
|
||||||
use DeepCopy\Filter\ChainableFilter;
|
|
||||||
use DeepCopy\Filter\Filter;
|
|
||||||
use DeepCopy\Matcher\Matcher;
|
|
||||||
use DeepCopy\Reflection\ReflectionHelper;
|
|
||||||
use DeepCopy\TypeFilter\Date\DateIntervalFilter;
|
|
||||||
use DeepCopy\TypeFilter\Spl\ArrayObjectFilter;
|
|
||||||
use DeepCopy\TypeFilter\Spl\SplDoublyLinkedListFilter;
|
|
||||||
use DeepCopy\TypeFilter\TypeFilter;
|
|
||||||
use DeepCopy\TypeMatcher\TypeMatcher;
|
|
||||||
use ReflectionObject;
|
|
||||||
use ReflectionProperty;
|
|
||||||
use SplDoublyLinkedList;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @final
|
|
||||||
*/
|
|
||||||
class DeepCopy
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var object[] List of objects copied.
|
|
||||||
*/
|
|
||||||
private $hashMap = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Filters to apply.
|
|
||||||
*
|
|
||||||
* @var array Array of ['filter' => Filter, 'matcher' => Matcher] pairs.
|
|
||||||
*/
|
|
||||||
private $filters = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Type Filters to apply.
|
|
||||||
*
|
|
||||||
* @var array Array of ['filter' => Filter, 'matcher' => Matcher] pairs.
|
|
||||||
*/
|
|
||||||
private $typeFilters = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var bool
|
|
||||||
*/
|
|
||||||
private $skipUncloneable = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var bool
|
|
||||||
*/
|
|
||||||
private $useCloneMethod;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param bool $useCloneMethod If set to true, when an object implements the __clone() function, it will be used
|
|
||||||
* instead of the regular deep cloning.
|
|
||||||
*/
|
|
||||||
public function __construct($useCloneMethod = false)
|
|
||||||
{
|
|
||||||
$this->useCloneMethod = $useCloneMethod;
|
|
||||||
|
|
||||||
$this->addTypeFilter(new ArrayObjectFilter($this), new TypeMatcher(ArrayObject::class));
|
|
||||||
$this->addTypeFilter(new DateIntervalFilter(), new TypeMatcher(DateInterval::class));
|
|
||||||
$this->addTypeFilter(new SplDoublyLinkedListFilter($this), new TypeMatcher(SplDoublyLinkedList::class));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* If enabled, will not throw an exception when coming across an uncloneable property.
|
|
||||||
*
|
|
||||||
* @param $skipUncloneable
|
|
||||||
*
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function skipUncloneable($skipUncloneable = true)
|
|
||||||
{
|
|
||||||
$this->skipUncloneable = $skipUncloneable;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deep copies the given object.
|
|
||||||
*
|
|
||||||
* @param mixed $object
|
|
||||||
*
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
public function copy($object)
|
|
||||||
{
|
|
||||||
$this->hashMap = [];
|
|
||||||
|
|
||||||
return $this->recursiveCopy($object);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function addFilter(Filter $filter, Matcher $matcher)
|
|
||||||
{
|
|
||||||
$this->filters[] = [
|
|
||||||
'matcher' => $matcher,
|
|
||||||
'filter' => $filter,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function prependFilter(Filter $filter, Matcher $matcher)
|
|
||||||
{
|
|
||||||
array_unshift($this->filters, [
|
|
||||||
'matcher' => $matcher,
|
|
||||||
'filter' => $filter,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function addTypeFilter(TypeFilter $filter, TypeMatcher $matcher)
|
|
||||||
{
|
|
||||||
$this->typeFilters[] = [
|
|
||||||
'matcher' => $matcher,
|
|
||||||
'filter' => $filter,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
private function recursiveCopy($var)
|
|
||||||
{
|
|
||||||
// Matches Type Filter
|
|
||||||
if ($filter = $this->getFirstMatchedTypeFilter($this->typeFilters, $var)) {
|
|
||||||
return $filter->apply($var);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Resource
|
|
||||||
if (is_resource($var)) {
|
|
||||||
return $var;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Array
|
|
||||||
if (is_array($var)) {
|
|
||||||
return $this->copyArray($var);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Scalar
|
|
||||||
if (! is_object($var)) {
|
|
||||||
return $var;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Enum
|
|
||||||
if (PHP_VERSION_ID >= 80100 && enum_exists(get_class($var))) {
|
|
||||||
return $var;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Object
|
|
||||||
return $this->copyObject($var);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copy an array
|
|
||||||
* @param array $array
|
|
||||||
* @return array
|
|
||||||
*/
|
|
||||||
private function copyArray(array $array)
|
|
||||||
{
|
|
||||||
foreach ($array as $key => $value) {
|
|
||||||
$array[$key] = $this->recursiveCopy($value);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $array;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Copies an object.
|
|
||||||
*
|
|
||||||
* @param object $object
|
|
||||||
*
|
|
||||||
* @throws CloneException
|
|
||||||
*
|
|
||||||
* @return object
|
|
||||||
*/
|
|
||||||
private function copyObject($object)
|
|
||||||
{
|
|
||||||
$objectHash = spl_object_hash($object);
|
|
||||||
|
|
||||||
if (isset($this->hashMap[$objectHash])) {
|
|
||||||
return $this->hashMap[$objectHash];
|
|
||||||
}
|
|
||||||
|
|
||||||
$reflectedObject = new ReflectionObject($object);
|
|
||||||
$isCloneable = $reflectedObject->isCloneable();
|
|
||||||
|
|
||||||
if (false === $isCloneable) {
|
|
||||||
if ($this->skipUncloneable) {
|
|
||||||
$this->hashMap[$objectHash] = $object;
|
|
||||||
|
|
||||||
return $object;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new CloneException(
|
|
||||||
sprintf(
|
|
||||||
'The class "%s" is not cloneable.',
|
|
||||||
$reflectedObject->getName()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
$newObject = clone $object;
|
|
||||||
$this->hashMap[$objectHash] = $newObject;
|
|
||||||
|
|
||||||
if ($this->useCloneMethod && $reflectedObject->hasMethod('__clone')) {
|
|
||||||
return $newObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($newObject instanceof DateTimeInterface || $newObject instanceof DateTimeZone) {
|
|
||||||
return $newObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (ReflectionHelper::getProperties($reflectedObject) as $property) {
|
|
||||||
$this->copyObjectProperty($newObject, $property);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $newObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function copyObjectProperty($object, ReflectionProperty $property)
|
|
||||||
{
|
|
||||||
// Ignore static properties
|
|
||||||
if ($property->isStatic()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply the filters
|
|
||||||
foreach ($this->filters as $item) {
|
|
||||||
/** @var Matcher $matcher */
|
|
||||||
$matcher = $item['matcher'];
|
|
||||||
/** @var Filter $filter */
|
|
||||||
$filter = $item['filter'];
|
|
||||||
|
|
||||||
if ($matcher->matches($object, $property->getName())) {
|
|
||||||
$filter->apply(
|
|
||||||
$object,
|
|
||||||
$property->getName(),
|
|
||||||
function ($object) {
|
|
||||||
return $this->recursiveCopy($object);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if ($filter instanceof ChainableFilter) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If a filter matches, we stop processing this property
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$property->setAccessible(true);
|
|
||||||
|
|
||||||
// Ignore uninitialized properties (for PHP >7.4)
|
|
||||||
if (method_exists($property, 'isInitialized') && !$property->isInitialized($object)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$propertyValue = $property->getValue($object);
|
|
||||||
|
|
||||||
// Copy the property
|
|
||||||
$property->setValue($object, $this->recursiveCopy($propertyValue));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns first filter that matches variable, `null` if no such filter found.
|
|
||||||
*
|
|
||||||
* @param array $filterRecords Associative array with 2 members: 'filter' with value of type {@see TypeFilter} and
|
|
||||||
* 'matcher' with value of type {@see TypeMatcher}
|
|
||||||
* @param mixed $var
|
|
||||||
*
|
|
||||||
* @return TypeFilter|null
|
|
||||||
*/
|
|
||||||
private function getFirstMatchedTypeFilter(array $filterRecords, $var)
|
|
||||||
{
|
|
||||||
$matched = $this->first(
|
|
||||||
$filterRecords,
|
|
||||||
function (array $record) use ($var) {
|
|
||||||
/* @var TypeMatcher $matcher */
|
|
||||||
$matcher = $record['matcher'];
|
|
||||||
|
|
||||||
return $matcher->matches($var);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return isset($matched) ? $matched['filter'] : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns first element that matches predicate, `null` if no such element found.
|
|
||||||
*
|
|
||||||
* @param array $elements Array of ['filter' => Filter, 'matcher' => Matcher] pairs.
|
|
||||||
* @param callable $predicate Predicate arguments are: element.
|
|
||||||
*
|
|
||||||
* @return array|null Associative array with 2 members: 'filter' with value of type {@see TypeFilter} and 'matcher'
|
|
||||||
* with value of type {@see TypeMatcher} or `null`.
|
|
||||||
*/
|
|
||||||
private function first(array $elements, callable $predicate)
|
|
||||||
{
|
|
||||||
foreach ($elements as $element) {
|
|
||||||
if (call_user_func($predicate, $element)) {
|
|
||||||
return $element;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace DeepCopy\Exception;
|
|
||||||
|
|
||||||
use UnexpectedValueException;
|
|
||||||
|
|
||||||
class CloneException extends UnexpectedValueException
|
|
||||||
{
|
|
||||||
}
|
|
@ -1,9 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace DeepCopy\Exception;
|
|
||||||
|
|
||||||
use ReflectionException;
|
|
||||||
|
|
||||||
class PropertyException extends ReflectionException
|
|
||||||
{
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace DeepCopy\Filter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines a decorator filter that will not stop the chain of filters.
|
|
||||||
*/
|
|
||||||
class ChainableFilter implements Filter
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var Filter
|
|
||||||
*/
|
|
||||||
protected $filter;
|
|
||||||
|
|
||||||
public function __construct(Filter $filter)
|
|
||||||
{
|
|
||||||
$this->filter = $filter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function apply($object, $property, $objectCopier)
|
|
||||||
{
|
|
||||||
$this->filter->apply($object, $property, $objectCopier);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace DeepCopy\Filter\Doctrine;
|
|
||||||
|
|
||||||
use DeepCopy\Filter\Filter;
|
|
||||||
use DeepCopy\Reflection\ReflectionHelper;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @final
|
|
||||||
*/
|
|
||||||
class DoctrineCollectionFilter implements Filter
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Copies the object property doctrine collection.
|
|
||||||
*
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function apply($object, $property, $objectCopier)
|
|
||||||
{
|
|
||||||
$reflectionProperty = ReflectionHelper::getProperty($object, $property);
|
|
||||||
|
|
||||||
$reflectionProperty->setAccessible(true);
|
|
||||||
$oldCollection = $reflectionProperty->getValue($object);
|
|
||||||
|
|
||||||
$newCollection = $oldCollection->map(
|
|
||||||
function ($item) use ($objectCopier) {
|
|
||||||
return $objectCopier($item);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
$reflectionProperty->setValue($object, $newCollection);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,28 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace DeepCopy\Filter\Doctrine;
|
|
||||||
|
|
||||||
use DeepCopy\Filter\Filter;
|
|
||||||
use DeepCopy\Reflection\ReflectionHelper;
|
|
||||||
use Doctrine\Common\Collections\ArrayCollection;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @final
|
|
||||||
*/
|
|
||||||
class DoctrineEmptyCollectionFilter implements Filter
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Sets the object property to an empty doctrine collection.
|
|
||||||
*
|
|
||||||
* @param object $object
|
|
||||||
* @param string $property
|
|
||||||
* @param callable $objectCopier
|
|
||||||
*/
|
|
||||||
public function apply($object, $property, $objectCopier)
|
|
||||||
{
|
|
||||||
$reflectionProperty = ReflectionHelper::getProperty($object, $property);
|
|
||||||
$reflectionProperty->setAccessible(true);
|
|
||||||
|
|
||||||
$reflectionProperty->setValue($object, new ArrayCollection());
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace DeepCopy\Filter\Doctrine;
|
|
||||||
|
|
||||||
use DeepCopy\Filter\Filter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @final
|
|
||||||
*/
|
|
||||||
class DoctrineProxyFilter implements Filter
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Triggers the magic method __load() on a Doctrine Proxy class to load the
|
|
||||||
* actual entity from the database.
|
|
||||||
*
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function apply($object, $property, $objectCopier)
|
|
||||||
{
|
|
||||||
$object->__load();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,18 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace DeepCopy\Filter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Filter to apply to a property while copying an object
|
|
||||||
*/
|
|
||||||
interface Filter
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Applies the filter to the object.
|
|
||||||
*
|
|
||||||
* @param object $object
|
|
||||||
* @param string $property
|
|
||||||
* @param callable $objectCopier
|
|
||||||
*/
|
|
||||||
public function apply($object, $property, $objectCopier);
|
|
||||||
}
|
|
@ -1,16 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace DeepCopy\Filter;
|
|
||||||
|
|
||||||
class KeepFilter implements Filter
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Keeps the value of the object property.
|
|
||||||
*
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function apply($object, $property, $objectCopier)
|
|
||||||
{
|
|
||||||
// Nothing to do
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace DeepCopy\Filter;
|
|
||||||
|
|
||||||
use DeepCopy\Reflection\ReflectionHelper;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @final
|
|
||||||
*/
|
|
||||||
class ReplaceFilter implements Filter
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var callable
|
|
||||||
*/
|
|
||||||
protected $callback;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param callable $callable Will be called to get the new value for each property to replace
|
|
||||||
*/
|
|
||||||
public function __construct(callable $callable)
|
|
||||||
{
|
|
||||||
$this->callback = $callable;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Replaces the object property by the result of the callback called with the object property.
|
|
||||||
*
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function apply($object, $property, $objectCopier)
|
|
||||||
{
|
|
||||||
$reflectionProperty = ReflectionHelper::getProperty($object, $property);
|
|
||||||
$reflectionProperty->setAccessible(true);
|
|
||||||
|
|
||||||
$value = call_user_func($this->callback, $reflectionProperty->getValue($object));
|
|
||||||
|
|
||||||
$reflectionProperty->setValue($object, $value);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,24 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace DeepCopy\Filter;
|
|
||||||
|
|
||||||
use DeepCopy\Reflection\ReflectionHelper;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @final
|
|
||||||
*/
|
|
||||||
class SetNullFilter implements Filter
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Sets the object property to null.
|
|
||||||
*
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function apply($object, $property, $objectCopier)
|
|
||||||
{
|
|
||||||
$reflectionProperty = ReflectionHelper::getProperty($object, $property);
|
|
||||||
|
|
||||||
$reflectionProperty->setAccessible(true);
|
|
||||||
$reflectionProperty->setValue($object, null);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,22 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace DeepCopy\Matcher\Doctrine;
|
|
||||||
|
|
||||||
use DeepCopy\Matcher\Matcher;
|
|
||||||
use Doctrine\Persistence\Proxy;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @final
|
|
||||||
*/
|
|
||||||
class DoctrineProxyMatcher implements Matcher
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Matches a Doctrine Proxy class.
|
|
||||||
*
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function matches($object, $property)
|
|
||||||
{
|
|
||||||
return $object instanceof Proxy;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,14 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace DeepCopy\Matcher;
|
|
||||||
|
|
||||||
interface Matcher
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @param object $object
|
|
||||||
* @param string $property
|
|
||||||
*
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function matches($object, $property);
|
|
||||||
}
|
|
@ -1,39 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace DeepCopy\Matcher;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @final
|
|
||||||
*/
|
|
||||||
class PropertyMatcher implements Matcher
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private $class;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private $property;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $class Class name
|
|
||||||
* @param string $property Property name
|
|
||||||
*/
|
|
||||||
public function __construct($class, $property)
|
|
||||||
{
|
|
||||||
$this->class = $class;
|
|
||||||
$this->property = $property;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Matches a specific property of a specific class.
|
|
||||||
*
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function matches($object, $property)
|
|
||||||
{
|
|
||||||
return ($object instanceof $this->class) && $property == $this->property;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,32 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace DeepCopy\Matcher;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @final
|
|
||||||
*/
|
|
||||||
class PropertyNameMatcher implements Matcher
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private $property;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $property Property name
|
|
||||||
*/
|
|
||||||
public function __construct($property)
|
|
||||||
{
|
|
||||||
$this->property = $property;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Matches a property by its name.
|
|
||||||
*
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function matches($object, $property)
|
|
||||||
{
|
|
||||||
return $property == $this->property;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,52 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace DeepCopy\Matcher;
|
|
||||||
|
|
||||||
use DeepCopy\Reflection\ReflectionHelper;
|
|
||||||
use ReflectionException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Matches a property by its type.
|
|
||||||
*
|
|
||||||
* It is recommended to use {@see DeepCopy\TypeFilter\TypeFilter} instead, as it applies on all occurrences
|
|
||||||
* of given type in copied context (eg. array elements), not just on object properties.
|
|
||||||
*
|
|
||||||
* @final
|
|
||||||
*/
|
|
||||||
class PropertyTypeMatcher implements Matcher
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private $propertyType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $propertyType Property type
|
|
||||||
*/
|
|
||||||
public function __construct($propertyType)
|
|
||||||
{
|
|
||||||
$this->propertyType = $propertyType;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function matches($object, $property)
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
$reflectionProperty = ReflectionHelper::getProperty($object, $property);
|
|
||||||
} catch (ReflectionException $exception) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
$reflectionProperty->setAccessible(true);
|
|
||||||
|
|
||||||
// Uninitialized properties (for PHP >7.4)
|
|
||||||
if (method_exists($reflectionProperty, 'isInitialized') && !$reflectionProperty->isInitialized($object)) {
|
|
||||||
// null instanceof $this->propertyType
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $reflectionProperty->getValue($object) instanceof $this->propertyType;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,78 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace DeepCopy\Reflection;
|
|
||||||
|
|
||||||
use DeepCopy\Exception\PropertyException;
|
|
||||||
use ReflectionClass;
|
|
||||||
use ReflectionException;
|
|
||||||
use ReflectionObject;
|
|
||||||
use ReflectionProperty;
|
|
||||||
|
|
||||||
class ReflectionHelper
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Retrieves all properties (including private ones), from object and all its ancestors.
|
|
||||||
*
|
|
||||||
* Standard \ReflectionClass->getProperties() does not return private properties from ancestor classes.
|
|
||||||
*
|
|
||||||
* @author muratyaman@gmail.com
|
|
||||||
* @see http://php.net/manual/en/reflectionclass.getproperties.php
|
|
||||||
*
|
|
||||||
* @param ReflectionClass $ref
|
|
||||||
*
|
|
||||||
* @return ReflectionProperty[]
|
|
||||||
*/
|
|
||||||
public static function getProperties(ReflectionClass $ref)
|
|
||||||
{
|
|
||||||
$props = $ref->getProperties();
|
|
||||||
$propsArr = array();
|
|
||||||
|
|
||||||
foreach ($props as $prop) {
|
|
||||||
$propertyName = $prop->getName();
|
|
||||||
$propsArr[$propertyName] = $prop;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($parentClass = $ref->getParentClass()) {
|
|
||||||
$parentPropsArr = self::getProperties($parentClass);
|
|
||||||
foreach ($propsArr as $key => $property) {
|
|
||||||
$parentPropsArr[$key] = $property;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $parentPropsArr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $propsArr;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieves property by name from object and all its ancestors.
|
|
||||||
*
|
|
||||||
* @param object|string $object
|
|
||||||
* @param string $name
|
|
||||||
*
|
|
||||||
* @throws PropertyException
|
|
||||||
* @throws ReflectionException
|
|
||||||
*
|
|
||||||
* @return ReflectionProperty
|
|
||||||
*/
|
|
||||||
public static function getProperty($object, $name)
|
|
||||||
{
|
|
||||||
$reflection = is_object($object) ? new ReflectionObject($object) : new ReflectionClass($object);
|
|
||||||
|
|
||||||
if ($reflection->hasProperty($name)) {
|
|
||||||
return $reflection->getProperty($name);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($parentClass = $reflection->getParentClass()) {
|
|
||||||
return self::getProperty($parentClass->getName(), $name);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new PropertyException(
|
|
||||||
sprintf(
|
|
||||||
'The class "%s" doesn\'t have a property with the given name: "%s".',
|
|
||||||
is_object($object) ? get_class($object) : $object,
|
|
||||||
$name
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,33 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace DeepCopy\TypeFilter\Date;
|
|
||||||
|
|
||||||
use DateInterval;
|
|
||||||
use DeepCopy\TypeFilter\TypeFilter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @final
|
|
||||||
*
|
|
||||||
* @deprecated Will be removed in 2.0. This filter will no longer be necessary in PHP 7.1+.
|
|
||||||
*/
|
|
||||||
class DateIntervalFilter implements TypeFilter
|
|
||||||
{
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*
|
|
||||||
* @param DateInterval $element
|
|
||||||
*
|
|
||||||
* @see http://news.php.net/php.bugs/205076
|
|
||||||
*/
|
|
||||||
public function apply($element)
|
|
||||||
{
|
|
||||||
$copy = new DateInterval('P0D');
|
|
||||||
|
|
||||||
foreach ($element as $propertyName => $propertyValue) {
|
|
||||||
$copy->{$propertyName} = $propertyValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $copy;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,30 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace DeepCopy\TypeFilter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @final
|
|
||||||
*/
|
|
||||||
class ReplaceFilter implements TypeFilter
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var callable
|
|
||||||
*/
|
|
||||||
protected $callback;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param callable $callable Will be called to get the new value for each element to replace
|
|
||||||
*/
|
|
||||||
public function __construct(callable $callable)
|
|
||||||
{
|
|
||||||
$this->callback = $callable;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function apply($element)
|
|
||||||
{
|
|
||||||
return call_user_func($this->callback, $element);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,17 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace DeepCopy\TypeFilter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @final
|
|
||||||
*/
|
|
||||||
class ShallowCopyFilter implements TypeFilter
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function apply($element)
|
|
||||||
{
|
|
||||||
return clone $element;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,36 +0,0 @@
|
|||||||
<?php
|
|
||||||
namespace DeepCopy\TypeFilter\Spl;
|
|
||||||
|
|
||||||
use DeepCopy\DeepCopy;
|
|
||||||
use DeepCopy\TypeFilter\TypeFilter;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* In PHP 7.4 the storage of an ArrayObject isn't returned as
|
|
||||||
* ReflectionProperty. So we deep copy its array copy.
|
|
||||||
*/
|
|
||||||
final class ArrayObjectFilter implements TypeFilter
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var DeepCopy
|
|
||||||
*/
|
|
||||||
private $copier;
|
|
||||||
|
|
||||||
public function __construct(DeepCopy $copier)
|
|
||||||
{
|
|
||||||
$this->copier = $copier;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function apply($arrayObject)
|
|
||||||
{
|
|
||||||
$clone = clone $arrayObject;
|
|
||||||
foreach ($arrayObject->getArrayCopy() as $k => $v) {
|
|
||||||
$clone->offsetSet($k, $this->copier->copy($v));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $clone;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace DeepCopy\TypeFilter\Spl;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated Use {@see SplDoublyLinkedListFilter} instead.
|
|
||||||
*/
|
|
||||||
class SplDoublyLinkedList extends SplDoublyLinkedListFilter
|
|
||||||
{
|
|
||||||
}
|
|
@ -1,51 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace DeepCopy\TypeFilter\Spl;
|
|
||||||
|
|
||||||
use Closure;
|
|
||||||
use DeepCopy\DeepCopy;
|
|
||||||
use DeepCopy\TypeFilter\TypeFilter;
|
|
||||||
use SplDoublyLinkedList;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @final
|
|
||||||
*/
|
|
||||||
class SplDoublyLinkedListFilter implements TypeFilter
|
|
||||||
{
|
|
||||||
private $copier;
|
|
||||||
|
|
||||||
public function __construct(DeepCopy $copier)
|
|
||||||
{
|
|
||||||
$this->copier = $copier;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritdoc}
|
|
||||||
*/
|
|
||||||
public function apply($element)
|
|
||||||
{
|
|
||||||
$newElement = clone $element;
|
|
||||||
|
|
||||||
$copy = $this->createCopyClosure();
|
|
||||||
|
|
||||||
return $copy($newElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
private function createCopyClosure()
|
|
||||||
{
|
|
||||||
$copier = $this->copier;
|
|
||||||
|
|
||||||
$copy = function (SplDoublyLinkedList $list) use ($copier) {
|
|
||||||
// Replace each element in the list with a deep copy of itself
|
|
||||||
for ($i = 1; $i <= $list->count(); $i++) {
|
|
||||||
$copy = $copier->recursiveCopy($list->shift());
|
|
||||||
|
|
||||||
$list->push($copy);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $list;
|
|
||||||
};
|
|
||||||
|
|
||||||
return Closure::bind($copy, null, DeepCopy::class);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,13 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace DeepCopy\TypeFilter;
|
|
||||||
|
|
||||||
interface TypeFilter
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* Applies the filter to the object.
|
|
||||||
*
|
|
||||||
* @param mixed $element
|
|
||||||
*/
|
|
||||||
public function apply($element);
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace DeepCopy\TypeMatcher;
|
|
||||||
|
|
||||||
class TypeMatcher
|
|
||||||
{
|
|
||||||
/**
|
|
||||||
* @var string
|
|
||||||
*/
|
|
||||||
private $type;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string $type
|
|
||||||
*/
|
|
||||||
public function __construct($type)
|
|
||||||
{
|
|
||||||
$this->type = $type;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param mixed $element
|
|
||||||
*
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public function matches($element)
|
|
||||||
{
|
|
||||||
return is_object($element) ? is_a($element, $this->type) : gettype($element) === $this->type;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,20 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
namespace DeepCopy;
|
|
||||||
|
|
||||||
use function function_exists;
|
|
||||||
|
|
||||||
if (false === function_exists('DeepCopy\deep_copy')) {
|
|
||||||
/**
|
|
||||||
* Deep copies the given value.
|
|
||||||
*
|
|
||||||
* @param mixed $value
|
|
||||||
* @param bool $useCloneMethod
|
|
||||||
*
|
|
||||||
* @return mixed
|
|
||||||
*/
|
|
||||||
function deep_copy($value, $useCloneMethod = false)
|
|
||||||
{
|
|
||||||
return (new DeepCopy($useCloneMethod))->copy($value);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
BSD 3-Clause License
|
|
||||||
|
|
||||||
Copyright (c) 2011, Nikita Popov
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Redistribution and use in source and binary forms, with or without
|
|
||||||
modification, are permitted provided that the following conditions are met:
|
|
||||||
|
|
||||||
1. Redistributions of source code must retain the above copyright notice, this
|
|
||||||
list of conditions and the following disclaimer.
|
|
||||||
|
|
||||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
||||||
this list of conditions and the following disclaimer in the documentation
|
|
||||||
and/or other materials provided with the distribution.
|
|
||||||
|
|
||||||
3. Neither the name of the copyright holder nor the names of its
|
|
||||||
contributors may be used to endorse or promote products derived from
|
|
||||||
this software without specific prior written permission.
|
|
||||||
|
|
||||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
||||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
||||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
||||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
||||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
||||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
||||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
||||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
||||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
||||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
@ -1,233 +0,0 @@
|
|||||||
PHP Parser
|
|
||||||
==========
|
|
||||||
|
|
||||||
[](https://coveralls.io/github/nikic/PHP-Parser?branch=master)
|
|
||||||
|
|
||||||
This is a PHP parser written in PHP. Its purpose is to simplify static code analysis and
|
|
||||||
manipulation.
|
|
||||||
|
|
||||||
[**Documentation for version 5.x**][doc_master] (current; for running on PHP >= 7.4; for parsing PHP 7.0 to PHP 8.3, with limited support for parsing PHP 5.x).
|
|
||||||
|
|
||||||
[Documentation for version 4.x][doc_4_x] (supported; for running on PHP >= 7.0; for parsing PHP 5.2 to PHP 8.3).
|
|
||||||
|
|
||||||
Features
|
|
||||||
--------
|
|
||||||
|
|
||||||
The main features provided by this library are:
|
|
||||||
|
|
||||||
* Parsing PHP 7, and PHP 8 code into an abstract syntax tree (AST).
|
|
||||||
* Invalid code can be parsed into a partial AST.
|
|
||||||
* The AST contains accurate location information.
|
|
||||||
* Dumping the AST in human-readable form.
|
|
||||||
* Converting an AST back to PHP code.
|
|
||||||
* Formatting can be preserved for partially changed ASTs.
|
|
||||||
* Infrastructure to traverse and modify ASTs.
|
|
||||||
* Resolution of namespaced names.
|
|
||||||
* Evaluation of constant expressions.
|
|
||||||
* Builders to simplify AST construction for code generation.
|
|
||||||
* Converting an AST into JSON and back.
|
|
||||||
|
|
||||||
Quick Start
|
|
||||||
-----------
|
|
||||||
|
|
||||||
Install the library using [composer](https://getcomposer.org):
|
|
||||||
|
|
||||||
php composer.phar require nikic/php-parser
|
|
||||||
|
|
||||||
Parse some PHP code into an AST and dump the result in human-readable form:
|
|
||||||
|
|
||||||
```php
|
|
||||||
<?php
|
|
||||||
use PhpParser\Error;
|
|
||||||
use PhpParser\NodeDumper;
|
|
||||||
use PhpParser\ParserFactory;
|
|
||||||
|
|
||||||
$code = <<<'CODE'
|
|
||||||
<?php
|
|
||||||
|
|
||||||
function test($foo)
|
|
||||||
{
|
|
||||||
var_dump($foo);
|
|
||||||
}
|
|
||||||
CODE;
|
|
||||||
|
|
||||||
$parser = (new ParserFactory())->createForNewestSupportedVersion();
|
|
||||||
try {
|
|
||||||
$ast = $parser->parse($code);
|
|
||||||
} catch (Error $error) {
|
|
||||||
echo "Parse error: {$error->getMessage()}\n";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$dumper = new NodeDumper;
|
|
||||||
echo $dumper->dump($ast) . "\n";
|
|
||||||
```
|
|
||||||
|
|
||||||
This dumps an AST looking something like this:
|
|
||||||
|
|
||||||
```
|
|
||||||
array(
|
|
||||||
0: Stmt_Function(
|
|
||||||
attrGroups: array(
|
|
||||||
)
|
|
||||||
byRef: false
|
|
||||||
name: Identifier(
|
|
||||||
name: test
|
|
||||||
)
|
|
||||||
params: array(
|
|
||||||
0: Param(
|
|
||||||
attrGroups: array(
|
|
||||||
)
|
|
||||||
flags: 0
|
|
||||||
type: null
|
|
||||||
byRef: false
|
|
||||||
variadic: false
|
|
||||||
var: Expr_Variable(
|
|
||||||
name: foo
|
|
||||||
)
|
|
||||||
default: null
|
|
||||||
)
|
|
||||||
)
|
|
||||||
returnType: null
|
|
||||||
stmts: array(
|
|
||||||
0: Stmt_Expression(
|
|
||||||
expr: Expr_FuncCall(
|
|
||||||
name: Name(
|
|
||||||
name: var_dump
|
|
||||||
)
|
|
||||||
args: array(
|
|
||||||
0: Arg(
|
|
||||||
name: null
|
|
||||||
value: Expr_Variable(
|
|
||||||
name: foo
|
|
||||||
)
|
|
||||||
byRef: false
|
|
||||||
unpack: false
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
Let's traverse the AST and perform some kind of modification. For example, drop all function bodies:
|
|
||||||
|
|
||||||
```php
|
|
||||||
use PhpParser\Node;
|
|
||||||
use PhpParser\Node\Stmt\Function_;
|
|
||||||
use PhpParser\NodeTraverser;
|
|
||||||
use PhpParser\NodeVisitorAbstract;
|
|
||||||
|
|
||||||
$traverser = new NodeTraverser();
|
|
||||||
$traverser->addVisitor(new class extends NodeVisitorAbstract {
|
|
||||||
public function enterNode(Node $node) {
|
|
||||||
if ($node instanceof Function_) {
|
|
||||||
// Clean out the function body
|
|
||||||
$node->stmts = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$ast = $traverser->traverse($ast);
|
|
||||||
echo $dumper->dump($ast) . "\n";
|
|
||||||
```
|
|
||||||
|
|
||||||
This gives us an AST where the `Function_::$stmts` are empty:
|
|
||||||
|
|
||||||
```
|
|
||||||
array(
|
|
||||||
0: Stmt_Function(
|
|
||||||
attrGroups: array(
|
|
||||||
)
|
|
||||||
byRef: false
|
|
||||||
name: Identifier(
|
|
||||||
name: test
|
|
||||||
)
|
|
||||||
params: array(
|
|
||||||
0: Param(
|
|
||||||
attrGroups: array(
|
|
||||||
)
|
|
||||||
type: null
|
|
||||||
byRef: false
|
|
||||||
variadic: false
|
|
||||||
var: Expr_Variable(
|
|
||||||
name: foo
|
|
||||||
)
|
|
||||||
default: null
|
|
||||||
)
|
|
||||||
)
|
|
||||||
returnType: null
|
|
||||||
stmts: array(
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
```
|
|
||||||
|
|
||||||
Finally, we can convert the new AST back to PHP code:
|
|
||||||
|
|
||||||
```php
|
|
||||||
use PhpParser\PrettyPrinter;
|
|
||||||
|
|
||||||
$prettyPrinter = new PrettyPrinter\Standard;
|
|
||||||
echo $prettyPrinter->prettyPrintFile($ast);
|
|
||||||
```
|
|
||||||
|
|
||||||
This gives us our original code, minus the `var_dump()` call inside the function:
|
|
||||||
|
|
||||||
```php
|
|
||||||
<?php
|
|
||||||
|
|
||||||
function test($foo)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
For a more comprehensive introduction, see the documentation.
|
|
||||||
|
|
||||||
Documentation
|
|
||||||
-------------
|
|
||||||
|
|
||||||
1. [Introduction](doc/0_Introduction.markdown)
|
|
||||||
2. [Usage of basic components](doc/2_Usage_of_basic_components.markdown)
|
|
||||||
|
|
||||||
Component documentation:
|
|
||||||
|
|
||||||
* [Walking the AST](doc/component/Walking_the_AST.markdown)
|
|
||||||
* Node visitors
|
|
||||||
* Modifying the AST from a visitor
|
|
||||||
* Short-circuiting traversals
|
|
||||||
* Interleaved visitors
|
|
||||||
* Simple node finding API
|
|
||||||
* Parent and sibling references
|
|
||||||
* [Name resolution](doc/component/Name_resolution.markdown)
|
|
||||||
* Name resolver options
|
|
||||||
* Name resolution context
|
|
||||||
* [Pretty printing](doc/component/Pretty_printing.markdown)
|
|
||||||
* Converting AST back to PHP code
|
|
||||||
* Customizing formatting
|
|
||||||
* Formatting-preserving code transformations
|
|
||||||
* [AST builders](doc/component/AST_builders.markdown)
|
|
||||||
* Fluent builders for AST nodes
|
|
||||||
* [Lexer](doc/component/Lexer.markdown)
|
|
||||||
* Emulation
|
|
||||||
* Tokens, positions and attributes
|
|
||||||
* [Error handling](doc/component/Error_handling.markdown)
|
|
||||||
* Column information for errors
|
|
||||||
* Error recovery (parsing of syntactically incorrect code)
|
|
||||||
* [Constant expression evaluation](doc/component/Constant_expression_evaluation.markdown)
|
|
||||||
* Evaluating constant/property/etc initializers
|
|
||||||
* Handling errors and unsupported expressions
|
|
||||||
* [JSON representation](doc/component/JSON_representation.markdown)
|
|
||||||
* JSON encoding and decoding of ASTs
|
|
||||||
* [Performance](doc/component/Performance.markdown)
|
|
||||||
* Disabling Xdebug
|
|
||||||
* Reusing objects
|
|
||||||
* Garbage collection impact
|
|
||||||
* [Frequently asked questions](doc/component/FAQ.markdown)
|
|
||||||
* Parent and sibling references
|
|
||||||
|
|
||||||
[doc_3_x]: https://github.com/nikic/PHP-Parser/tree/3.x/doc
|
|
||||||
[doc_4_x]: https://github.com/nikic/PHP-Parser/tree/4.x/doc
|
|
||||||
[doc_master]: https://github.com/nikic/PHP-Parser/tree/master/doc
|
|
@ -1,43 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "nikic/php-parser",
|
|
||||||
"type": "library",
|
|
||||||
"description": "A PHP parser written in PHP",
|
|
||||||
"keywords": [
|
|
||||||
"php",
|
|
||||||
"parser"
|
|
||||||
],
|
|
||||||
"license": "BSD-3-Clause",
|
|
||||||
"authors": [
|
|
||||||
{
|
|
||||||
"name": "Nikita Popov"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"require": {
|
|
||||||
"php": ">=7.4",
|
|
||||||
"ext-tokenizer": "*",
|
|
||||||
"ext-json": "*",
|
|
||||||
"ext-ctype": "*"
|
|
||||||
},
|
|
||||||
"require-dev": {
|
|
||||||
"phpunit/phpunit": "^7.0 || ^8.0 || ^9.0",
|
|
||||||
"ircmaxell/php-yacc": "^0.0.7"
|
|
||||||
},
|
|
||||||
"extra": {
|
|
||||||
"branch-alias": {
|
|
||||||
"dev-master": "5.0-dev"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"autoload": {
|
|
||||||
"psr-4": {
|
|
||||||
"PhpParser\\": "lib/PhpParser"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"autoload-dev": {
|
|
||||||
"psr-4": {
|
|
||||||
"PhpParser\\": "test/PhpParser/"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"bin": [
|
|
||||||
"bin/php-parse"
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
<?php declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace PhpParser;
|
|
||||||
|
|
||||||
interface Builder {
|
|
||||||
/**
|
|
||||||
* Returns the built node.
|
|
||||||
*
|
|
||||||
* @return Node The built node
|
|
||||||
*/
|
|
||||||
public function getNode(): Node;
|
|
||||||
}
|
|
@ -1,150 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace PhpParser\Builder;
|
|
||||||
|
|
||||||
use PhpParser;
|
|
||||||
use PhpParser\BuilderHelpers;
|
|
||||||
use PhpParser\Modifiers;
|
|
||||||
use PhpParser\Node;
|
|
||||||
use PhpParser\Node\Const_;
|
|
||||||
use PhpParser\Node\Identifier;
|
|
||||||
use PhpParser\Node\Stmt;
|
|
||||||
|
|
||||||
class ClassConst implements PhpParser\Builder {
|
|
||||||
protected int $flags = 0;
|
|
||||||
/** @var array<string, mixed> */
|
|
||||||
protected array $attributes = [];
|
|
||||||
/** @var list<Const_> */
|
|
||||||
protected array $constants = [];
|
|
||||||
|
|
||||||
/** @var list<Node\AttributeGroup> */
|
|
||||||
protected array $attributeGroups = [];
|
|
||||||
/** @var Identifier|Node\Name|Node\ComplexType|null */
|
|
||||||
protected ?Node $type = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a class constant builder
|
|
||||||
*
|
|
||||||
* @param string|Identifier $name Name
|
|
||||||
* @param Node\Expr|bool|null|int|float|string|array $value Value
|
|
||||||
*/
|
|
||||||
public function __construct($name, $value) {
|
|
||||||
$this->constants = [new Const_($name, BuilderHelpers::normalizeValue($value))];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add another constant to const group
|
|
||||||
*
|
|
||||||
* @param string|Identifier $name Name
|
|
||||||
* @param Node\Expr|bool|null|int|float|string|array $value Value
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function addConst($name, $value) {
|
|
||||||
$this->constants[] = new Const_($name, BuilderHelpers::normalizeValue($value));
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes the constant public.
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function makePublic() {
|
|
||||||
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PUBLIC);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes the constant protected.
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function makeProtected() {
|
|
||||||
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PROTECTED);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes the constant private.
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function makePrivate() {
|
|
||||||
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PRIVATE);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes the constant final.
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function makeFinal() {
|
|
||||||
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::FINAL);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets doc comment for the constant.
|
|
||||||
*
|
|
||||||
* @param PhpParser\Comment\Doc|string $docComment Doc comment to set
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function setDocComment($docComment) {
|
|
||||||
$this->attributes = [
|
|
||||||
'comments' => [BuilderHelpers::normalizeDocComment($docComment)]
|
|
||||||
];
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an attribute group.
|
|
||||||
*
|
|
||||||
* @param Node\Attribute|Node\AttributeGroup $attribute
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function addAttribute($attribute) {
|
|
||||||
$this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the constant type.
|
|
||||||
*
|
|
||||||
* @param string|Node\Name|Identifier|Node\ComplexType $type
|
|
||||||
*
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function setType($type) {
|
|
||||||
$this->type = BuilderHelpers::normalizeType($type);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the built class node.
|
|
||||||
*
|
|
||||||
* @return Stmt\ClassConst The built constant node
|
|
||||||
*/
|
|
||||||
public function getNode(): PhpParser\Node {
|
|
||||||
return new Stmt\ClassConst(
|
|
||||||
$this->constants,
|
|
||||||
$this->flags,
|
|
||||||
$this->attributes,
|
|
||||||
$this->attributeGroups,
|
|
||||||
$this->type
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,151 +0,0 @@
|
|||||||
<?php declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace PhpParser\Builder;
|
|
||||||
|
|
||||||
use PhpParser;
|
|
||||||
use PhpParser\BuilderHelpers;
|
|
||||||
use PhpParser\Modifiers;
|
|
||||||
use PhpParser\Node;
|
|
||||||
use PhpParser\Node\Name;
|
|
||||||
use PhpParser\Node\Stmt;
|
|
||||||
|
|
||||||
class Class_ extends Declaration {
|
|
||||||
protected string $name;
|
|
||||||
protected ?Name $extends = null;
|
|
||||||
/** @var list<Name> */
|
|
||||||
protected array $implements = [];
|
|
||||||
protected int $flags = 0;
|
|
||||||
/** @var list<Stmt\TraitUse> */
|
|
||||||
protected array $uses = [];
|
|
||||||
/** @var list<Stmt\ClassConst> */
|
|
||||||
protected array $constants = [];
|
|
||||||
/** @var list<Stmt\Property> */
|
|
||||||
protected array $properties = [];
|
|
||||||
/** @var list<Stmt\ClassMethod> */
|
|
||||||
protected array $methods = [];
|
|
||||||
/** @var list<Node\AttributeGroup> */
|
|
||||||
protected array $attributeGroups = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a class builder.
|
|
||||||
*
|
|
||||||
* @param string $name Name of the class
|
|
||||||
*/
|
|
||||||
public function __construct(string $name) {
|
|
||||||
$this->name = $name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extends a class.
|
|
||||||
*
|
|
||||||
* @param Name|string $class Name of class to extend
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function extend($class) {
|
|
||||||
$this->extends = BuilderHelpers::normalizeName($class);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements one or more interfaces.
|
|
||||||
*
|
|
||||||
* @param Name|string ...$interfaces Names of interfaces to implement
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function implement(...$interfaces) {
|
|
||||||
foreach ($interfaces as $interface) {
|
|
||||||
$this->implements[] = BuilderHelpers::normalizeName($interface);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes the class abstract.
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function makeAbstract() {
|
|
||||||
$this->flags = BuilderHelpers::addClassModifier($this->flags, Modifiers::ABSTRACT);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes the class final.
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function makeFinal() {
|
|
||||||
$this->flags = BuilderHelpers::addClassModifier($this->flags, Modifiers::FINAL);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes the class readonly.
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function makeReadonly() {
|
|
||||||
$this->flags = BuilderHelpers::addClassModifier($this->flags, Modifiers::READONLY);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a statement.
|
|
||||||
*
|
|
||||||
* @param Stmt|PhpParser\Builder $stmt The statement to add
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function addStmt($stmt) {
|
|
||||||
$stmt = BuilderHelpers::normalizeNode($stmt);
|
|
||||||
|
|
||||||
if ($stmt instanceof Stmt\Property) {
|
|
||||||
$this->properties[] = $stmt;
|
|
||||||
} elseif ($stmt instanceof Stmt\ClassMethod) {
|
|
||||||
$this->methods[] = $stmt;
|
|
||||||
} elseif ($stmt instanceof Stmt\TraitUse) {
|
|
||||||
$this->uses[] = $stmt;
|
|
||||||
} elseif ($stmt instanceof Stmt\ClassConst) {
|
|
||||||
$this->constants[] = $stmt;
|
|
||||||
} else {
|
|
||||||
throw new \LogicException(sprintf('Unexpected node of type "%s"', $stmt->getType()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an attribute group.
|
|
||||||
*
|
|
||||||
* @param Node\Attribute|Node\AttributeGroup $attribute
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function addAttribute($attribute) {
|
|
||||||
$this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the built class node.
|
|
||||||
*
|
|
||||||
* @return Stmt\Class_ The built class node
|
|
||||||
*/
|
|
||||||
public function getNode(): PhpParser\Node {
|
|
||||||
return new Stmt\Class_($this->name, [
|
|
||||||
'flags' => $this->flags,
|
|
||||||
'extends' => $this->extends,
|
|
||||||
'implements' => $this->implements,
|
|
||||||
'stmts' => array_merge($this->uses, $this->constants, $this->properties, $this->methods),
|
|
||||||
'attrGroups' => $this->attributeGroups,
|
|
||||||
], $this->attributes);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,50 +0,0 @@
|
|||||||
<?php declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace PhpParser\Builder;
|
|
||||||
|
|
||||||
use PhpParser;
|
|
||||||
use PhpParser\BuilderHelpers;
|
|
||||||
|
|
||||||
abstract class Declaration implements PhpParser\Builder {
|
|
||||||
/** @var array<string, mixed> */
|
|
||||||
protected array $attributes = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a statement.
|
|
||||||
*
|
|
||||||
* @param PhpParser\Node\Stmt|PhpParser\Builder $stmt The statement to add
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
abstract public function addStmt($stmt);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds multiple statements.
|
|
||||||
*
|
|
||||||
* @param (PhpParser\Node\Stmt|PhpParser\Builder)[] $stmts The statements to add
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function addStmts(array $stmts) {
|
|
||||||
foreach ($stmts as $stmt) {
|
|
||||||
$this->addStmt($stmt);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets doc comment for the declaration.
|
|
||||||
*
|
|
||||||
* @param PhpParser\Comment\Doc|string $docComment Doc comment to set
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function setDocComment($docComment) {
|
|
||||||
$this->attributes['comments'] = [
|
|
||||||
BuilderHelpers::normalizeDocComment($docComment)
|
|
||||||
];
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,87 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace PhpParser\Builder;
|
|
||||||
|
|
||||||
use PhpParser;
|
|
||||||
use PhpParser\BuilderHelpers;
|
|
||||||
use PhpParser\Node;
|
|
||||||
use PhpParser\Node\Identifier;
|
|
||||||
use PhpParser\Node\Stmt;
|
|
||||||
|
|
||||||
class EnumCase implements PhpParser\Builder {
|
|
||||||
/** @var Identifier|string */
|
|
||||||
protected $name;
|
|
||||||
/** @var ?Node\Expr */
|
|
||||||
protected ?Node\Expr $value = null;
|
|
||||||
/** @var array<string, mixed> */
|
|
||||||
protected array $attributes = [];
|
|
||||||
|
|
||||||
/** @var list<Node\AttributeGroup> */
|
|
||||||
protected array $attributeGroups = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an enum case builder.
|
|
||||||
*
|
|
||||||
* @param string|Identifier $name Name
|
|
||||||
*/
|
|
||||||
public function __construct($name) {
|
|
||||||
$this->name = $name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the value.
|
|
||||||
*
|
|
||||||
* @param Node\Expr|string|int $value
|
|
||||||
*
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function setValue($value) {
|
|
||||||
$this->value = BuilderHelpers::normalizeValue($value);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets doc comment for the constant.
|
|
||||||
*
|
|
||||||
* @param PhpParser\Comment\Doc|string $docComment Doc comment to set
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function setDocComment($docComment) {
|
|
||||||
$this->attributes = [
|
|
||||||
'comments' => [BuilderHelpers::normalizeDocComment($docComment)]
|
|
||||||
];
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an attribute group.
|
|
||||||
*
|
|
||||||
* @param Node\Attribute|Node\AttributeGroup $attribute
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function addAttribute($attribute) {
|
|
||||||
$this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the built enum case node.
|
|
||||||
*
|
|
||||||
* @return Stmt\EnumCase The built constant node
|
|
||||||
*/
|
|
||||||
public function getNode(): PhpParser\Node {
|
|
||||||
return new Stmt\EnumCase(
|
|
||||||
$this->name,
|
|
||||||
$this->value,
|
|
||||||
$this->attributeGroups,
|
|
||||||
$this->attributes
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,116 +0,0 @@
|
|||||||
<?php declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace PhpParser\Builder;
|
|
||||||
|
|
||||||
use PhpParser;
|
|
||||||
use PhpParser\BuilderHelpers;
|
|
||||||
use PhpParser\Node;
|
|
||||||
use PhpParser\Node\Identifier;
|
|
||||||
use PhpParser\Node\Name;
|
|
||||||
use PhpParser\Node\Stmt;
|
|
||||||
|
|
||||||
class Enum_ extends Declaration {
|
|
||||||
protected string $name;
|
|
||||||
protected ?Identifier $scalarType = null;
|
|
||||||
/** @var list<Name> */
|
|
||||||
protected array $implements = [];
|
|
||||||
/** @var list<Stmt\TraitUse> */
|
|
||||||
protected array $uses = [];
|
|
||||||
/** @var list<Stmt\EnumCase> */
|
|
||||||
protected array $enumCases = [];
|
|
||||||
/** @var list<Stmt\ClassConst> */
|
|
||||||
protected array $constants = [];
|
|
||||||
/** @var list<Stmt\ClassMethod> */
|
|
||||||
protected array $methods = [];
|
|
||||||
/** @var list<Node\AttributeGroup> */
|
|
||||||
protected array $attributeGroups = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an enum builder.
|
|
||||||
*
|
|
||||||
* @param string $name Name of the enum
|
|
||||||
*/
|
|
||||||
public function __construct(string $name) {
|
|
||||||
$this->name = $name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the scalar type.
|
|
||||||
*
|
|
||||||
* @param string|Identifier $scalarType
|
|
||||||
*
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function setScalarType($scalarType) {
|
|
||||||
$this->scalarType = BuilderHelpers::normalizeType($scalarType);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implements one or more interfaces.
|
|
||||||
*
|
|
||||||
* @param Name|string ...$interfaces Names of interfaces to implement
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function implement(...$interfaces) {
|
|
||||||
foreach ($interfaces as $interface) {
|
|
||||||
$this->implements[] = BuilderHelpers::normalizeName($interface);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a statement.
|
|
||||||
*
|
|
||||||
* @param Stmt|PhpParser\Builder $stmt The statement to add
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function addStmt($stmt) {
|
|
||||||
$stmt = BuilderHelpers::normalizeNode($stmt);
|
|
||||||
|
|
||||||
if ($stmt instanceof Stmt\EnumCase) {
|
|
||||||
$this->enumCases[] = $stmt;
|
|
||||||
} elseif ($stmt instanceof Stmt\ClassMethod) {
|
|
||||||
$this->methods[] = $stmt;
|
|
||||||
} elseif ($stmt instanceof Stmt\TraitUse) {
|
|
||||||
$this->uses[] = $stmt;
|
|
||||||
} elseif ($stmt instanceof Stmt\ClassConst) {
|
|
||||||
$this->constants[] = $stmt;
|
|
||||||
} else {
|
|
||||||
throw new \LogicException(sprintf('Unexpected node of type "%s"', $stmt->getType()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an attribute group.
|
|
||||||
*
|
|
||||||
* @param Node\Attribute|Node\AttributeGroup $attribute
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function addAttribute($attribute) {
|
|
||||||
$this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the built class node.
|
|
||||||
*
|
|
||||||
* @return Stmt\Enum_ The built enum node
|
|
||||||
*/
|
|
||||||
public function getNode(): PhpParser\Node {
|
|
||||||
return new Stmt\Enum_($this->name, [
|
|
||||||
'scalarType' => $this->scalarType,
|
|
||||||
'implements' => $this->implements,
|
|
||||||
'stmts' => array_merge($this->uses, $this->enumCases, $this->constants, $this->methods),
|
|
||||||
'attrGroups' => $this->attributeGroups,
|
|
||||||
], $this->attributes);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,73 +0,0 @@
|
|||||||
<?php declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace PhpParser\Builder;
|
|
||||||
|
|
||||||
use PhpParser\BuilderHelpers;
|
|
||||||
use PhpParser\Node;
|
|
||||||
|
|
||||||
abstract class FunctionLike extends Declaration {
|
|
||||||
protected bool $returnByRef = false;
|
|
||||||
/** @var Node\Param[] */
|
|
||||||
protected array $params = [];
|
|
||||||
|
|
||||||
/** @var Node\Identifier|Node\Name|Node\ComplexType|null */
|
|
||||||
protected ?Node $returnType = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Make the function return by reference.
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function makeReturnByRef() {
|
|
||||||
$this->returnByRef = true;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a parameter.
|
|
||||||
*
|
|
||||||
* @param Node\Param|Param $param The parameter to add
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function addParam($param) {
|
|
||||||
$param = BuilderHelpers::normalizeNode($param);
|
|
||||||
|
|
||||||
if (!$param instanceof Node\Param) {
|
|
||||||
throw new \LogicException(sprintf('Expected parameter node, got "%s"', $param->getType()));
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->params[] = $param;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds multiple parameters.
|
|
||||||
*
|
|
||||||
* @param (Node\Param|Param)[] $params The parameters to add
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function addParams(array $params) {
|
|
||||||
foreach ($params as $param) {
|
|
||||||
$this->addParam($param);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the return type for PHP 7.
|
|
||||||
*
|
|
||||||
* @param string|Node\Name|Node\Identifier|Node\ComplexType $type
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function setReturnType($type) {
|
|
||||||
$this->returnType = BuilderHelpers::normalizeType($type);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,67 +0,0 @@
|
|||||||
<?php declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace PhpParser\Builder;
|
|
||||||
|
|
||||||
use PhpParser;
|
|
||||||
use PhpParser\BuilderHelpers;
|
|
||||||
use PhpParser\Node;
|
|
||||||
use PhpParser\Node\Stmt;
|
|
||||||
|
|
||||||
class Function_ extends FunctionLike {
|
|
||||||
protected string $name;
|
|
||||||
/** @var list<Stmt> */
|
|
||||||
protected array $stmts = [];
|
|
||||||
|
|
||||||
/** @var list<Node\AttributeGroup> */
|
|
||||||
protected array $attributeGroups = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a function builder.
|
|
||||||
*
|
|
||||||
* @param string $name Name of the function
|
|
||||||
*/
|
|
||||||
public function __construct(string $name) {
|
|
||||||
$this->name = $name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a statement.
|
|
||||||
*
|
|
||||||
* @param Node|PhpParser\Builder $stmt The statement to add
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function addStmt($stmt) {
|
|
||||||
$this->stmts[] = BuilderHelpers::normalizeStmt($stmt);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an attribute group.
|
|
||||||
*
|
|
||||||
* @param Node\Attribute|Node\AttributeGroup $attribute
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function addAttribute($attribute) {
|
|
||||||
$this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the built function node.
|
|
||||||
*
|
|
||||||
* @return Stmt\Function_ The built function node
|
|
||||||
*/
|
|
||||||
public function getNode(): Node {
|
|
||||||
return new Stmt\Function_($this->name, [
|
|
||||||
'byRef' => $this->returnByRef,
|
|
||||||
'params' => $this->params,
|
|
||||||
'returnType' => $this->returnType,
|
|
||||||
'stmts' => $this->stmts,
|
|
||||||
'attrGroups' => $this->attributeGroups,
|
|
||||||
], $this->attributes);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,94 +0,0 @@
|
|||||||
<?php declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace PhpParser\Builder;
|
|
||||||
|
|
||||||
use PhpParser;
|
|
||||||
use PhpParser\BuilderHelpers;
|
|
||||||
use PhpParser\Node;
|
|
||||||
use PhpParser\Node\Name;
|
|
||||||
use PhpParser\Node\Stmt;
|
|
||||||
|
|
||||||
class Interface_ extends Declaration {
|
|
||||||
protected string $name;
|
|
||||||
/** @var list<Name> */
|
|
||||||
protected array $extends = [];
|
|
||||||
/** @var list<Stmt\ClassConst> */
|
|
||||||
protected array $constants = [];
|
|
||||||
/** @var list<Stmt\ClassMethod> */
|
|
||||||
protected array $methods = [];
|
|
||||||
/** @var list<Node\AttributeGroup> */
|
|
||||||
protected array $attributeGroups = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an interface builder.
|
|
||||||
*
|
|
||||||
* @param string $name Name of the interface
|
|
||||||
*/
|
|
||||||
public function __construct(string $name) {
|
|
||||||
$this->name = $name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extends one or more interfaces.
|
|
||||||
*
|
|
||||||
* @param Name|string ...$interfaces Names of interfaces to extend
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function extend(...$interfaces) {
|
|
||||||
foreach ($interfaces as $interface) {
|
|
||||||
$this->extends[] = BuilderHelpers::normalizeName($interface);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a statement.
|
|
||||||
*
|
|
||||||
* @param Stmt|PhpParser\Builder $stmt The statement to add
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function addStmt($stmt) {
|
|
||||||
$stmt = BuilderHelpers::normalizeNode($stmt);
|
|
||||||
|
|
||||||
if ($stmt instanceof Stmt\ClassConst) {
|
|
||||||
$this->constants[] = $stmt;
|
|
||||||
} elseif ($stmt instanceof Stmt\ClassMethod) {
|
|
||||||
// we erase all statements in the body of an interface method
|
|
||||||
$stmt->stmts = null;
|
|
||||||
$this->methods[] = $stmt;
|
|
||||||
} else {
|
|
||||||
throw new \LogicException(sprintf('Unexpected node of type "%s"', $stmt->getType()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an attribute group.
|
|
||||||
*
|
|
||||||
* @param Node\Attribute|Node\AttributeGroup $attribute
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function addAttribute($attribute) {
|
|
||||||
$this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the built interface node.
|
|
||||||
*
|
|
||||||
* @return Stmt\Interface_ The built interface node
|
|
||||||
*/
|
|
||||||
public function getNode(): PhpParser\Node {
|
|
||||||
return new Stmt\Interface_($this->name, [
|
|
||||||
'extends' => $this->extends,
|
|
||||||
'stmts' => array_merge($this->constants, $this->methods),
|
|
||||||
'attrGroups' => $this->attributeGroups,
|
|
||||||
], $this->attributes);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,147 +0,0 @@
|
|||||||
<?php declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace PhpParser\Builder;
|
|
||||||
|
|
||||||
use PhpParser;
|
|
||||||
use PhpParser\BuilderHelpers;
|
|
||||||
use PhpParser\Modifiers;
|
|
||||||
use PhpParser\Node;
|
|
||||||
use PhpParser\Node\Stmt;
|
|
||||||
|
|
||||||
class Method extends FunctionLike {
|
|
||||||
protected string $name;
|
|
||||||
|
|
||||||
protected int $flags = 0;
|
|
||||||
|
|
||||||
/** @var list<Stmt>|null */
|
|
||||||
protected ?array $stmts = [];
|
|
||||||
|
|
||||||
/** @var list<Node\AttributeGroup> */
|
|
||||||
protected array $attributeGroups = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a method builder.
|
|
||||||
*
|
|
||||||
* @param string $name Name of the method
|
|
||||||
*/
|
|
||||||
public function __construct(string $name) {
|
|
||||||
$this->name = $name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes the method public.
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function makePublic() {
|
|
||||||
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PUBLIC);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes the method protected.
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function makeProtected() {
|
|
||||||
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PROTECTED);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes the method private.
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function makePrivate() {
|
|
||||||
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PRIVATE);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes the method static.
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function makeStatic() {
|
|
||||||
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::STATIC);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes the method abstract.
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function makeAbstract() {
|
|
||||||
if (!empty($this->stmts)) {
|
|
||||||
throw new \LogicException('Cannot make method with statements abstract');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::ABSTRACT);
|
|
||||||
$this->stmts = null; // abstract methods don't have statements
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes the method final.
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function makeFinal() {
|
|
||||||
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::FINAL);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a statement.
|
|
||||||
*
|
|
||||||
* @param Node|PhpParser\Builder $stmt The statement to add
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function addStmt($stmt) {
|
|
||||||
if (null === $this->stmts) {
|
|
||||||
throw new \LogicException('Cannot add statements to an abstract method');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->stmts[] = BuilderHelpers::normalizeStmt($stmt);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an attribute group.
|
|
||||||
*
|
|
||||||
* @param Node\Attribute|Node\AttributeGroup $attribute
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function addAttribute($attribute) {
|
|
||||||
$this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the built method node.
|
|
||||||
*
|
|
||||||
* @return Stmt\ClassMethod The built method node
|
|
||||||
*/
|
|
||||||
public function getNode(): Node {
|
|
||||||
return new Stmt\ClassMethod($this->name, [
|
|
||||||
'flags' => $this->flags,
|
|
||||||
'byRef' => $this->returnByRef,
|
|
||||||
'params' => $this->params,
|
|
||||||
'returnType' => $this->returnType,
|
|
||||||
'stmts' => $this->stmts,
|
|
||||||
'attrGroups' => $this->attributeGroups,
|
|
||||||
], $this->attributes);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,45 +0,0 @@
|
|||||||
<?php declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace PhpParser\Builder;
|
|
||||||
|
|
||||||
use PhpParser;
|
|
||||||
use PhpParser\BuilderHelpers;
|
|
||||||
use PhpParser\Node;
|
|
||||||
use PhpParser\Node\Stmt;
|
|
||||||
|
|
||||||
class Namespace_ extends Declaration {
|
|
||||||
private ?Node\Name $name;
|
|
||||||
/** @var Stmt[] */
|
|
||||||
private array $stmts = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a namespace builder.
|
|
||||||
*
|
|
||||||
* @param Node\Name|string|null $name Name of the namespace
|
|
||||||
*/
|
|
||||||
public function __construct($name) {
|
|
||||||
$this->name = null !== $name ? BuilderHelpers::normalizeName($name) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a statement.
|
|
||||||
*
|
|
||||||
* @param Node|PhpParser\Builder $stmt The statement to add
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function addStmt($stmt) {
|
|
||||||
$this->stmts[] = BuilderHelpers::normalizeStmt($stmt);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the built node.
|
|
||||||
*
|
|
||||||
* @return Stmt\Namespace_ The built node
|
|
||||||
*/
|
|
||||||
public function getNode(): Node {
|
|
||||||
return new Stmt\Namespace_($this->name, $this->stmts, $this->attributes);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,149 +0,0 @@
|
|||||||
<?php declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace PhpParser\Builder;
|
|
||||||
|
|
||||||
use PhpParser;
|
|
||||||
use PhpParser\BuilderHelpers;
|
|
||||||
use PhpParser\Modifiers;
|
|
||||||
use PhpParser\Node;
|
|
||||||
|
|
||||||
class Param implements PhpParser\Builder {
|
|
||||||
protected string $name;
|
|
||||||
protected ?Node\Expr $default = null;
|
|
||||||
/** @var Node\Identifier|Node\Name|Node\ComplexType|null */
|
|
||||||
protected ?Node $type = null;
|
|
||||||
protected bool $byRef = false;
|
|
||||||
protected int $flags = 0;
|
|
||||||
protected bool $variadic = false;
|
|
||||||
/** @var list<Node\AttributeGroup> */
|
|
||||||
protected array $attributeGroups = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a parameter builder.
|
|
||||||
*
|
|
||||||
* @param string $name Name of the parameter
|
|
||||||
*/
|
|
||||||
public function __construct(string $name) {
|
|
||||||
$this->name = $name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets default value for the parameter.
|
|
||||||
*
|
|
||||||
* @param mixed $value Default value to use
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function setDefault($value) {
|
|
||||||
$this->default = BuilderHelpers::normalizeValue($value);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets type for the parameter.
|
|
||||||
*
|
|
||||||
* @param string|Node\Name|Node\Identifier|Node\ComplexType $type Parameter type
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function setType($type) {
|
|
||||||
$this->type = BuilderHelpers::normalizeType($type);
|
|
||||||
if ($this->type == 'void') {
|
|
||||||
throw new \LogicException('Parameter type cannot be void');
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Make the parameter accept the value by reference.
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function makeByRef() {
|
|
||||||
$this->byRef = true;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Make the parameter variadic
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function makeVariadic() {
|
|
||||||
$this->variadic = true;
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes the (promoted) parameter public.
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function makePublic() {
|
|
||||||
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PUBLIC);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes the (promoted) parameter protected.
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function makeProtected() {
|
|
||||||
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PROTECTED);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes the (promoted) parameter private.
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function makePrivate() {
|
|
||||||
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PRIVATE);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes the (promoted) parameter readonly.
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function makeReadonly() {
|
|
||||||
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::READONLY);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an attribute group.
|
|
||||||
*
|
|
||||||
* @param Node\Attribute|Node\AttributeGroup $attribute
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function addAttribute($attribute) {
|
|
||||||
$this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the built parameter node.
|
|
||||||
*
|
|
||||||
* @return Node\Param The built parameter node
|
|
||||||
*/
|
|
||||||
public function getNode(): Node {
|
|
||||||
return new Node\Param(
|
|
||||||
new Node\Expr\Variable($this->name),
|
|
||||||
$this->default, $this->type, $this->byRef, $this->variadic, [], $this->flags, $this->attributeGroups
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,161 +0,0 @@
|
|||||||
<?php declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace PhpParser\Builder;
|
|
||||||
|
|
||||||
use PhpParser;
|
|
||||||
use PhpParser\BuilderHelpers;
|
|
||||||
use PhpParser\Modifiers;
|
|
||||||
use PhpParser\Node;
|
|
||||||
use PhpParser\Node\Identifier;
|
|
||||||
use PhpParser\Node\Name;
|
|
||||||
use PhpParser\Node\Stmt;
|
|
||||||
use PhpParser\Node\ComplexType;
|
|
||||||
|
|
||||||
class Property implements PhpParser\Builder {
|
|
||||||
protected string $name;
|
|
||||||
|
|
||||||
protected int $flags = 0;
|
|
||||||
|
|
||||||
protected ?Node\Expr $default = null;
|
|
||||||
/** @var array<string, mixed> */
|
|
||||||
protected array $attributes = [];
|
|
||||||
/** @var null|Identifier|Name|ComplexType */
|
|
||||||
protected ?Node $type = null;
|
|
||||||
/** @var list<Node\AttributeGroup> */
|
|
||||||
protected array $attributeGroups = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a property builder.
|
|
||||||
*
|
|
||||||
* @param string $name Name of the property
|
|
||||||
*/
|
|
||||||
public function __construct(string $name) {
|
|
||||||
$this->name = $name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes the property public.
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function makePublic() {
|
|
||||||
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PUBLIC);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes the property protected.
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function makeProtected() {
|
|
||||||
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PROTECTED);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes the property private.
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function makePrivate() {
|
|
||||||
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::PRIVATE);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes the property static.
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function makeStatic() {
|
|
||||||
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::STATIC);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Makes the property readonly.
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function makeReadonly() {
|
|
||||||
$this->flags = BuilderHelpers::addModifier($this->flags, Modifiers::READONLY);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets default value for the property.
|
|
||||||
*
|
|
||||||
* @param mixed $value Default value to use
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function setDefault($value) {
|
|
||||||
$this->default = BuilderHelpers::normalizeValue($value);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets doc comment for the property.
|
|
||||||
*
|
|
||||||
* @param PhpParser\Comment\Doc|string $docComment Doc comment to set
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function setDocComment($docComment) {
|
|
||||||
$this->attributes = [
|
|
||||||
'comments' => [BuilderHelpers::normalizeDocComment($docComment)]
|
|
||||||
];
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets the property type for PHP 7.4+.
|
|
||||||
*
|
|
||||||
* @param string|Name|Identifier|ComplexType $type
|
|
||||||
*
|
|
||||||
* @return $this
|
|
||||||
*/
|
|
||||||
public function setType($type) {
|
|
||||||
$this->type = BuilderHelpers::normalizeType($type);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an attribute group.
|
|
||||||
*
|
|
||||||
* @param Node\Attribute|Node\AttributeGroup $attribute
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function addAttribute($attribute) {
|
|
||||||
$this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the built class node.
|
|
||||||
*
|
|
||||||
* @return Stmt\Property The built property node
|
|
||||||
*/
|
|
||||||
public function getNode(): PhpParser\Node {
|
|
||||||
return new Stmt\Property(
|
|
||||||
$this->flags !== 0 ? $this->flags : Modifiers::PUBLIC,
|
|
||||||
[
|
|
||||||
new Node\PropertyItem($this->name, $this->default)
|
|
||||||
],
|
|
||||||
$this->attributes,
|
|
||||||
$this->type,
|
|
||||||
$this->attributeGroups
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,65 +0,0 @@
|
|||||||
<?php declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace PhpParser\Builder;
|
|
||||||
|
|
||||||
use PhpParser\Builder;
|
|
||||||
use PhpParser\BuilderHelpers;
|
|
||||||
use PhpParser\Node;
|
|
||||||
use PhpParser\Node\Stmt;
|
|
||||||
|
|
||||||
class TraitUse implements Builder {
|
|
||||||
/** @var Node\Name[] */
|
|
||||||
protected array $traits = [];
|
|
||||||
/** @var Stmt\TraitUseAdaptation[] */
|
|
||||||
protected array $adaptations = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a trait use builder.
|
|
||||||
*
|
|
||||||
* @param Node\Name|string ...$traits Names of used traits
|
|
||||||
*/
|
|
||||||
public function __construct(...$traits) {
|
|
||||||
foreach ($traits as $trait) {
|
|
||||||
$this->and($trait);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds used trait.
|
|
||||||
*
|
|
||||||
* @param Node\Name|string $trait Trait name
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function and($trait) {
|
|
||||||
$this->traits[] = BuilderHelpers::normalizeName($trait);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds trait adaptation.
|
|
||||||
*
|
|
||||||
* @param Stmt\TraitUseAdaptation|Builder\TraitUseAdaptation $adaptation Trait adaptation
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function with($adaptation) {
|
|
||||||
$adaptation = BuilderHelpers::normalizeNode($adaptation);
|
|
||||||
|
|
||||||
if (!$adaptation instanceof Stmt\TraitUseAdaptation) {
|
|
||||||
throw new \LogicException('Adaptation must have type TraitUseAdaptation');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->adaptations[] = $adaptation;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the built node.
|
|
||||||
*
|
|
||||||
* @return Node The built node
|
|
||||||
*/
|
|
||||||
public function getNode(): Node {
|
|
||||||
return new Stmt\TraitUse($this->traits, $this->adaptations);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,145 +0,0 @@
|
|||||||
<?php declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace PhpParser\Builder;
|
|
||||||
|
|
||||||
use PhpParser\Builder;
|
|
||||||
use PhpParser\BuilderHelpers;
|
|
||||||
use PhpParser\Modifiers;
|
|
||||||
use PhpParser\Node;
|
|
||||||
use PhpParser\Node\Stmt;
|
|
||||||
|
|
||||||
class TraitUseAdaptation implements Builder {
|
|
||||||
private const TYPE_UNDEFINED = 0;
|
|
||||||
private const TYPE_ALIAS = 1;
|
|
||||||
private const TYPE_PRECEDENCE = 2;
|
|
||||||
|
|
||||||
protected int $type;
|
|
||||||
protected ?Node\Name $trait;
|
|
||||||
protected Node\Identifier $method;
|
|
||||||
protected ?int $modifier = null;
|
|
||||||
protected ?Node\Identifier $alias = null;
|
|
||||||
/** @var Node\Name[] */
|
|
||||||
protected array $insteadof = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a trait use adaptation builder.
|
|
||||||
*
|
|
||||||
* @param Node\Name|string|null $trait Name of adapted trait
|
|
||||||
* @param Node\Identifier|string $method Name of adapted method
|
|
||||||
*/
|
|
||||||
public function __construct($trait, $method) {
|
|
||||||
$this->type = self::TYPE_UNDEFINED;
|
|
||||||
|
|
||||||
$this->trait = is_null($trait) ? null : BuilderHelpers::normalizeName($trait);
|
|
||||||
$this->method = BuilderHelpers::normalizeIdentifier($method);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets alias of method.
|
|
||||||
*
|
|
||||||
* @param Node\Identifier|string $alias Alias for adapted method
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function as($alias) {
|
|
||||||
if ($this->type === self::TYPE_UNDEFINED) {
|
|
||||||
$this->type = self::TYPE_ALIAS;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->type !== self::TYPE_ALIAS) {
|
|
||||||
throw new \LogicException('Cannot set alias for not alias adaptation buider');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->alias = BuilderHelpers::normalizeIdentifier($alias);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets adapted method public.
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function makePublic() {
|
|
||||||
$this->setModifier(Modifiers::PUBLIC);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets adapted method protected.
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function makeProtected() {
|
|
||||||
$this->setModifier(Modifiers::PROTECTED);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets adapted method private.
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function makePrivate() {
|
|
||||||
$this->setModifier(Modifiers::PRIVATE);
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds overwritten traits.
|
|
||||||
*
|
|
||||||
* @param Node\Name|string ...$traits Traits for overwrite
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function insteadof(...$traits) {
|
|
||||||
if ($this->type === self::TYPE_UNDEFINED) {
|
|
||||||
if (is_null($this->trait)) {
|
|
||||||
throw new \LogicException('Precedence adaptation must have trait');
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->type = self::TYPE_PRECEDENCE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->type !== self::TYPE_PRECEDENCE) {
|
|
||||||
throw new \LogicException('Cannot add overwritten traits for not precedence adaptation buider');
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach ($traits as $trait) {
|
|
||||||
$this->insteadof[] = BuilderHelpers::normalizeName($trait);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function setModifier(int $modifier): void {
|
|
||||||
if ($this->type === self::TYPE_UNDEFINED) {
|
|
||||||
$this->type = self::TYPE_ALIAS;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($this->type !== self::TYPE_ALIAS) {
|
|
||||||
throw new \LogicException('Cannot set access modifier for not alias adaptation buider');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_null($this->modifier)) {
|
|
||||||
$this->modifier = $modifier;
|
|
||||||
} else {
|
|
||||||
throw new \LogicException('Multiple access type modifiers are not allowed');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the built node.
|
|
||||||
*
|
|
||||||
* @return Node The built node
|
|
||||||
*/
|
|
||||||
public function getNode(): Node {
|
|
||||||
switch ($this->type) {
|
|
||||||
case self::TYPE_ALIAS:
|
|
||||||
return new Stmt\TraitUseAdaptation\Alias($this->trait, $this->method, $this->modifier, $this->alias);
|
|
||||||
case self::TYPE_PRECEDENCE:
|
|
||||||
return new Stmt\TraitUseAdaptation\Precedence($this->trait, $this->method, $this->insteadof);
|
|
||||||
default:
|
|
||||||
throw new \LogicException('Type of adaptation is not defined');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,83 +0,0 @@
|
|||||||
<?php declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace PhpParser\Builder;
|
|
||||||
|
|
||||||
use PhpParser;
|
|
||||||
use PhpParser\BuilderHelpers;
|
|
||||||
use PhpParser\Node;
|
|
||||||
use PhpParser\Node\Stmt;
|
|
||||||
|
|
||||||
class Trait_ extends Declaration {
|
|
||||||
protected string $name;
|
|
||||||
/** @var list<Stmt\TraitUse> */
|
|
||||||
protected array $uses = [];
|
|
||||||
/** @var list<Stmt\ClassConst> */
|
|
||||||
protected array $constants = [];
|
|
||||||
/** @var list<Stmt\Property> */
|
|
||||||
protected array $properties = [];
|
|
||||||
/** @var list<Stmt\ClassMethod> */
|
|
||||||
protected array $methods = [];
|
|
||||||
/** @var list<Node\AttributeGroup> */
|
|
||||||
protected array $attributeGroups = [];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an interface builder.
|
|
||||||
*
|
|
||||||
* @param string $name Name of the interface
|
|
||||||
*/
|
|
||||||
public function __construct(string $name) {
|
|
||||||
$this->name = $name;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds a statement.
|
|
||||||
*
|
|
||||||
* @param Stmt|PhpParser\Builder $stmt The statement to add
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function addStmt($stmt) {
|
|
||||||
$stmt = BuilderHelpers::normalizeNode($stmt);
|
|
||||||
|
|
||||||
if ($stmt instanceof Stmt\Property) {
|
|
||||||
$this->properties[] = $stmt;
|
|
||||||
} elseif ($stmt instanceof Stmt\ClassMethod) {
|
|
||||||
$this->methods[] = $stmt;
|
|
||||||
} elseif ($stmt instanceof Stmt\TraitUse) {
|
|
||||||
$this->uses[] = $stmt;
|
|
||||||
} elseif ($stmt instanceof Stmt\ClassConst) {
|
|
||||||
$this->constants[] = $stmt;
|
|
||||||
} else {
|
|
||||||
throw new \LogicException(sprintf('Unexpected node of type "%s"', $stmt->getType()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds an attribute group.
|
|
||||||
*
|
|
||||||
* @param Node\Attribute|Node\AttributeGroup $attribute
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function addAttribute($attribute) {
|
|
||||||
$this->attributeGroups[] = BuilderHelpers::normalizeAttribute($attribute);
|
|
||||||
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the built trait node.
|
|
||||||
*
|
|
||||||
* @return Stmt\Trait_ The built interface node
|
|
||||||
*/
|
|
||||||
public function getNode(): PhpParser\Node {
|
|
||||||
return new Stmt\Trait_(
|
|
||||||
$this->name, [
|
|
||||||
'stmts' => array_merge($this->uses, $this->constants, $this->properties, $this->methods),
|
|
||||||
'attrGroups' => $this->attributeGroups,
|
|
||||||
], $this->attributes
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,49 +0,0 @@
|
|||||||
<?php declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace PhpParser\Builder;
|
|
||||||
|
|
||||||
use PhpParser\Builder;
|
|
||||||
use PhpParser\BuilderHelpers;
|
|
||||||
use PhpParser\Node;
|
|
||||||
use PhpParser\Node\Stmt;
|
|
||||||
|
|
||||||
class Use_ implements Builder {
|
|
||||||
protected Node\Name $name;
|
|
||||||
/** @var Stmt\Use_::TYPE_* */
|
|
||||||
protected int $type;
|
|
||||||
protected ?string $alias = null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a name use (alias) builder.
|
|
||||||
*
|
|
||||||
* @param Node\Name|string $name Name of the entity (namespace, class, function, constant) to alias
|
|
||||||
* @param Stmt\Use_::TYPE_* $type One of the Stmt\Use_::TYPE_* constants
|
|
||||||
*/
|
|
||||||
public function __construct($name, int $type) {
|
|
||||||
$this->name = BuilderHelpers::normalizeName($name);
|
|
||||||
$this->type = $type;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets alias for used name.
|
|
||||||
*
|
|
||||||
* @param string $alias Alias to use (last component of full name by default)
|
|
||||||
*
|
|
||||||
* @return $this The builder instance (for fluid interface)
|
|
||||||
*/
|
|
||||||
public function as(string $alias) {
|
|
||||||
$this->alias = $alias;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the built node.
|
|
||||||
*
|
|
||||||
* @return Stmt\Use_ The built node
|
|
||||||
*/
|
|
||||||
public function getNode(): Node {
|
|
||||||
return new Stmt\Use_([
|
|
||||||
new Node\UseItem($this->name, $this->alias)
|
|
||||||
], $this->type);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,375 +0,0 @@
|
|||||||
<?php declare(strict_types=1);
|
|
||||||
|
|
||||||
namespace PhpParser;
|
|
||||||
|
|
||||||
use PhpParser\Node\Arg;
|
|
||||||
use PhpParser\Node\Expr;
|
|
||||||
use PhpParser\Node\Expr\BinaryOp\Concat;
|
|
||||||
use PhpParser\Node\Identifier;
|
|
||||||
use PhpParser\Node\Name;
|
|
||||||
use PhpParser\Node\Scalar\String_;
|
|
||||||
use PhpParser\Node\Stmt\Use_;
|
|
||||||
|
|
||||||
class BuilderFactory {
|
|
||||||
/**
|
|
||||||
* Creates an attribute node.
|
|
||||||
*
|
|
||||||
* @param string|Name $name Name of the attribute
|
|
||||||
* @param array $args Attribute named arguments
|
|
||||||
*/
|
|
||||||
public function attribute($name, array $args = []): Node\Attribute {
|
|
||||||
return new Node\Attribute(
|
|
||||||
BuilderHelpers::normalizeName($name),
|
|
||||||
$this->args($args)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a namespace builder.
|
|
||||||
*
|
|
||||||
* @param null|string|Node\Name $name Name of the namespace
|
|
||||||
*
|
|
||||||
* @return Builder\Namespace_ The created namespace builder
|
|
||||||
*/
|
|
||||||
public function namespace($name): Builder\Namespace_ {
|
|
||||||
return new Builder\Namespace_($name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a class builder.
|
|
||||||
*
|
|
||||||
* @param string $name Name of the class
|
|
||||||
*
|
|
||||||
* @return Builder\Class_ The created class builder
|
|
||||||
*/
|
|
||||||
public function class(string $name): Builder\Class_ {
|
|
||||||
return new Builder\Class_($name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an interface builder.
|
|
||||||
*
|
|
||||||
* @param string $name Name of the interface
|
|
||||||
*
|
|
||||||
* @return Builder\Interface_ The created interface builder
|
|
||||||
*/
|
|
||||||
public function interface(string $name): Builder\Interface_ {
|
|
||||||
return new Builder\Interface_($name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a trait builder.
|
|
||||||
*
|
|
||||||
* @param string $name Name of the trait
|
|
||||||
*
|
|
||||||
* @return Builder\Trait_ The created trait builder
|
|
||||||
*/
|
|
||||||
public function trait(string $name): Builder\Trait_ {
|
|
||||||
return new Builder\Trait_($name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an enum builder.
|
|
||||||
*
|
|
||||||
* @param string $name Name of the enum
|
|
||||||
*
|
|
||||||
* @return Builder\Enum_ The created enum builder
|
|
||||||
*/
|
|
||||||
public function enum(string $name): Builder\Enum_ {
|
|
||||||
return new Builder\Enum_($name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a trait use builder.
|
|
||||||
*
|
|
||||||
* @param Node\Name|string ...$traits Trait names
|
|
||||||
*
|
|
||||||
* @return Builder\TraitUse The created trait use builder
|
|
||||||
*/
|
|
||||||
public function useTrait(...$traits): Builder\TraitUse {
|
|
||||||
return new Builder\TraitUse(...$traits);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a trait use adaptation builder.
|
|
||||||
*
|
|
||||||
* @param Node\Name|string|null $trait Trait name
|
|
||||||
* @param Node\Identifier|string $method Method name
|
|
||||||
*
|
|
||||||
* @return Builder\TraitUseAdaptation The created trait use adaptation builder
|
|
||||||
*/
|
|
||||||
public function traitUseAdaptation($trait, $method = null): Builder\TraitUseAdaptation {
|
|
||||||
if ($method === null) {
|
|
||||||
$method = $trait;
|
|
||||||
$trait = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Builder\TraitUseAdaptation($trait, $method);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a method builder.
|
|
||||||
*
|
|
||||||
* @param string $name Name of the method
|
|
||||||
*
|
|
||||||
* @return Builder\Method The created method builder
|
|
||||||
*/
|
|
||||||
public function method(string $name): Builder\Method {
|
|
||||||
return new Builder\Method($name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a parameter builder.
|
|
||||||
*
|
|
||||||
* @param string $name Name of the parameter
|
|
||||||
*
|
|
||||||
* @return Builder\Param The created parameter builder
|
|
||||||
*/
|
|
||||||
public function param(string $name): Builder\Param {
|
|
||||||
return new Builder\Param($name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a property builder.
|
|
||||||
*
|
|
||||||
* @param string $name Name of the property
|
|
||||||
*
|
|
||||||
* @return Builder\Property The created property builder
|
|
||||||
*/
|
|
||||||
public function property(string $name): Builder\Property {
|
|
||||||
return new Builder\Property($name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a function builder.
|
|
||||||
*
|
|
||||||
* @param string $name Name of the function
|
|
||||||
*
|
|
||||||
* @return Builder\Function_ The created function builder
|
|
||||||
*/
|
|
||||||
public function function(string $name): Builder\Function_ {
|
|
||||||
return new Builder\Function_($name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a namespace/class use builder.
|
|
||||||
*
|
|
||||||
* @param Node\Name|string $name Name of the entity (namespace or class) to alias
|
|
||||||
*
|
|
||||||
* @return Builder\Use_ The created use builder
|
|
||||||
*/
|
|
||||||
public function use($name): Builder\Use_ {
|
|
||||||
return new Builder\Use_($name, Use_::TYPE_NORMAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a function use builder.
|
|
||||||
*
|
|
||||||
* @param Node\Name|string $name Name of the function to alias
|
|
||||||
*
|
|
||||||
* @return Builder\Use_ The created use function builder
|
|
||||||
*/
|
|
||||||
public function useFunction($name): Builder\Use_ {
|
|
||||||
return new Builder\Use_($name, Use_::TYPE_FUNCTION);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a constant use builder.
|
|
||||||
*
|
|
||||||
* @param Node\Name|string $name Name of the const to alias
|
|
||||||
*
|
|
||||||
* @return Builder\Use_ The created use const builder
|
|
||||||
*/
|
|
||||||
public function useConst($name): Builder\Use_ {
|
|
||||||
return new Builder\Use_($name, Use_::TYPE_CONSTANT);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a class constant builder.
|
|
||||||
*
|
|
||||||
* @param string|Identifier $name Name
|
|
||||||
* @param Node\Expr|bool|null|int|float|string|array $value Value
|
|
||||||
*
|
|
||||||
* @return Builder\ClassConst The created use const builder
|
|
||||||
*/
|
|
||||||
public function classConst($name, $value): Builder\ClassConst {
|
|
||||||
return new Builder\ClassConst($name, $value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an enum case builder.
|
|
||||||
*
|
|
||||||
* @param string|Identifier $name Name
|
|
||||||
*
|
|
||||||
* @return Builder\EnumCase The created use const builder
|
|
||||||
*/
|
|
||||||
public function enumCase($name): Builder\EnumCase {
|
|
||||||
return new Builder\EnumCase($name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates node a for a literal value.
|
|
||||||
*
|
|
||||||
* @param Expr|bool|null|int|float|string|array $value $value
|
|
||||||
*/
|
|
||||||
public function val($value): Expr {
|
|
||||||
return BuilderHelpers::normalizeValue($value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates variable node.
|
|
||||||
*
|
|
||||||
* @param string|Expr $name Name
|
|
||||||
*/
|
|
||||||
public function var($name): Expr\Variable {
|
|
||||||
if (!\is_string($name) && !$name instanceof Expr) {
|
|
||||||
throw new \LogicException('Variable name must be string or Expr');
|
|
||||||
}
|
|
||||||
|
|
||||||
return new Expr\Variable($name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Normalizes an argument list.
|
|
||||||
*
|
|
||||||
* Creates Arg nodes for all arguments and converts literal values to expressions.
|
|
||||||
*
|
|
||||||
* @param array $args List of arguments to normalize
|
|
||||||
*
|
|
||||||
* @return list<Arg>
|
|
||||||
*/
|
|
||||||
public function args(array $args): array {
|
|
||||||
$normalizedArgs = [];
|
|
||||||
foreach ($args as $key => $arg) {
|
|
||||||
if (!($arg instanceof Arg)) {
|
|
||||||
$arg = new Arg(BuilderHelpers::normalizeValue($arg));
|
|
||||||
}
|
|
||||||
if (\is_string($key)) {
|
|
||||||
$arg->name = BuilderHelpers::normalizeIdentifier($key);
|
|
||||||
}
|
|
||||||
$normalizedArgs[] = $arg;
|
|
||||||
}
|
|
||||||
return $normalizedArgs;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a function call node.
|
|
||||||
*
|
|
||||||
* @param string|Name|Expr $name Function name
|
|
||||||
* @param array $args Function arguments
|
|
||||||
*/
|
|
||||||
public function funcCall($name, array $args = []): Expr\FuncCall {
|
|
||||||
return new Expr\FuncCall(
|
|
||||||
BuilderHelpers::normalizeNameOrExpr($name),
|
|
||||||
$this->args($args)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a method call node.
|
|
||||||
*
|
|
||||||
* @param Expr $var Variable the method is called on
|
|
||||||
* @param string|Identifier|Expr $name Method name
|
|
||||||
* @param array $args Method arguments
|
|
||||||
*/
|
|
||||||
public function methodCall(Expr $var, $name, array $args = []): Expr\MethodCall {
|
|
||||||
return new Expr\MethodCall(
|
|
||||||
$var,
|
|
||||||
BuilderHelpers::normalizeIdentifierOrExpr($name),
|
|
||||||
$this->args($args)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a static method call node.
|
|
||||||
*
|
|
||||||
* @param string|Name|Expr $class Class name
|
|
||||||
* @param string|Identifier|Expr $name Method name
|
|
||||||
* @param array $args Method arguments
|
|
||||||
*/
|
|
||||||
public function staticCall($class, $name, array $args = []): Expr\StaticCall {
|
|
||||||
return new Expr\StaticCall(
|
|
||||||
BuilderHelpers::normalizeNameOrExpr($class),
|
|
||||||
BuilderHelpers::normalizeIdentifierOrExpr($name),
|
|
||||||
$this->args($args)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates an object creation node.
|
|
||||||
*
|
|
||||||
* @param string|Name|Expr $class Class name
|
|
||||||
* @param array $args Constructor arguments
|
|
||||||
*/
|
|
||||||
public function new($class, array $args = []): Expr\New_ {
|
|
||||||
return new Expr\New_(
|
|
||||||
BuilderHelpers::normalizeNameOrExpr($class),
|
|
||||||
$this->args($args)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a constant fetch node.
|
|
||||||
*
|
|
||||||
* @param string|Name $name Constant name
|
|
||||||
*/
|
|
||||||
public function constFetch($name): Expr\ConstFetch {
|
|
||||||
return new Expr\ConstFetch(BuilderHelpers::normalizeName($name));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a property fetch node.
|
|
||||||
*
|
|
||||||
* @param Expr $var Variable holding object
|
|
||||||
* @param string|Identifier|Expr $name Property name
|
|
||||||
*/
|
|
||||||
public function propertyFetch(Expr $var, $name): Expr\PropertyFetch {
|
|
||||||
return new Expr\PropertyFetch($var, BuilderHelpers::normalizeIdentifierOrExpr($name));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a class constant fetch node.
|
|
||||||
*
|
|
||||||
* @param string|Name|Expr $class Class name
|
|
||||||
* @param string|Identifier|Expr $name Constant name
|
|
||||||
*/
|
|
||||||
public function classConstFetch($class, $name): Expr\ClassConstFetch {
|
|
||||||
return new Expr\ClassConstFetch(
|
|
||||||
BuilderHelpers::normalizeNameOrExpr($class),
|
|
||||||
BuilderHelpers::normalizeIdentifierOrExpr($name)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates nested Concat nodes from a list of expressions.
|
|
||||||
*
|
|
||||||
* @param Expr|string ...$exprs Expressions or literal strings
|
|
||||||
*/
|
|
||||||
public function concat(...$exprs): Concat {
|
|
||||||
$numExprs = count($exprs);
|
|
||||||
if ($numExprs < 2) {
|
|
||||||
throw new \LogicException('Expected at least two expressions');
|
|
||||||
}
|
|
||||||
|
|
||||||
$lastConcat = $this->normalizeStringExpr($exprs[0]);
|
|
||||||
for ($i = 1; $i < $numExprs; $i++) {
|
|
||||||
$lastConcat = new Concat($lastConcat, $this->normalizeStringExpr($exprs[$i]));
|
|
||||||
}
|
|
||||||
return $lastConcat;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param string|Expr $expr
|
|
||||||
*/
|
|
||||||
private function normalizeStringExpr($expr): Expr {
|
|
||||||
if ($expr instanceof Expr) {
|
|
||||||
return $expr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (\is_string($expr)) {
|
|
||||||
return new String_($expr);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new \LogicException('Expected string or Expr');
|
|
||||||
}
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue