diff --git a/.github/workflows/unittests.yml b/.github/workflows/unittests.yml
index 97bcf1d3..250245ec 100644
--- a/.github/workflows/unittests.yml
+++ b/.github/workflows/unittests.yml
@@ -12,7 +12,7 @@ jobs:
strategy:
matrix:
os: ['ubuntu-latest']
- php: ['8.1', '8.2', '8.3']
+ php: ['8.1', '8.2', '8.3', '8.4']
steps:
- name: Set locales
run: |
diff --git a/composer.json b/composer.json
index 17ae72b6..d9c1877e 100644
--- a/composer.json
+++ b/composer.json
@@ -30,7 +30,7 @@
}
],
"require": {
- "php": "~8.1.0 || ~8.2.0 || ~8.3.0",
+ "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0",
"ext-dom": "*",
"ext-gettext": "*",
"ext-simplexml": "*",
diff --git a/composer.lock b/composer.lock
index 51610267..b270188a 100644
--- a/composer.lock
+++ b/composer.lock
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
- "content-hash": "7c8d4ab932aea5ac49373502f5c5539a",
+ "content-hash": "070a0e5770a4dab12e3e5c1a6ec82eb0",
"packages": [
{
"name": "symfony/polyfill-mbstring",
@@ -903,16 +903,16 @@
},
{
"name": "phpstan/phpstan",
- "version": "1.12.11",
+ "version": "1.12.12",
"source": {
"type": "git",
"url": "https://github.com/phpstan/phpstan.git",
- "reference": "0d1fc20a962a91be578bcfe7cf939e6e1a2ff733"
+ "reference": "b5ae1b88f471d3fd4ba1aa0046234b5ca3776dd0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/phpstan/phpstan/zipball/0d1fc20a962a91be578bcfe7cf939e6e1a2ff733",
- "reference": "0d1fc20a962a91be578bcfe7cf939e6e1a2ff733",
+ "url": "https://api.github.com/repos/phpstan/phpstan/zipball/b5ae1b88f471d3fd4ba1aa0046234b5ca3776dd0",
+ "reference": "b5ae1b88f471d3fd4ba1aa0046234b5ca3776dd0",
"shasum": ""
},
"require": {
@@ -957,7 +957,7 @@
"type": "github"
}
],
- "time": "2024-11-17T14:08:01+00:00"
+ "time": "2024-11-28T22:13:23+00:00"
},
{
"name": "phpunit/php-code-coverage",
@@ -3135,16 +3135,16 @@
},
{
"name": "symfony/deprecation-contracts",
- "version": "v3.5.0",
+ "version": "v3.5.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git",
- "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1"
+ "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1",
- "reference": "0e0d29ce1f20deffb4ab1b016a7257c4f1e789a1",
+ "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6",
+ "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6",
"shasum": ""
},
"require": {
@@ -3182,7 +3182,7 @@
"description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com",
"support": {
- "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.0"
+ "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1"
},
"funding": [
{
@@ -3198,7 +3198,7 @@
"type": "tidelift"
}
],
- "time": "2024-04-18T09:32:20+00:00"
+ "time": "2024-09-25T14:20:29+00:00"
},
{
"name": "symfony/event-dispatcher",
@@ -3282,16 +3282,16 @@
},
{
"name": "symfony/event-dispatcher-contracts",
- "version": "v3.5.0",
+ "version": "v3.5.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/event-dispatcher-contracts.git",
- "reference": "8f93aec25d41b72493c6ddff14e916177c9efc50"
+ "reference": "7642f5e970b672283b7823222ae8ef8bbc160b9f"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/8f93aec25d41b72493c6ddff14e916177c9efc50",
- "reference": "8f93aec25d41b72493c6ddff14e916177c9efc50",
+ "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/7642f5e970b672283b7823222ae8ef8bbc160b9f",
+ "reference": "7642f5e970b672283b7823222ae8ef8bbc160b9f",
"shasum": ""
},
"require": {
@@ -3338,7 +3338,7 @@
"standards"
],
"support": {
- "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.5.0"
+ "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.5.1"
},
"funding": [
{
@@ -3354,7 +3354,7 @@
"type": "tidelift"
}
],
- "time": "2024-04-18T09:32:20+00:00"
+ "time": "2024-09-25T14:20:29+00:00"
},
{
"name": "symfony/filesystem",
@@ -3488,16 +3488,16 @@
},
{
"name": "symfony/options-resolver",
- "version": "v6.4.13",
+ "version": "v6.4.16",
"source": {
"type": "git",
"url": "https://github.com/symfony/options-resolver.git",
- "reference": "0a62a9f2504a8dd27083f89d21894ceb01cc59db"
+ "reference": "368128ad168f20e22c32159b9f761e456cec0c78"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/options-resolver/zipball/0a62a9f2504a8dd27083f89d21894ceb01cc59db",
- "reference": "0a62a9f2504a8dd27083f89d21894ceb01cc59db",
+ "url": "https://api.github.com/repos/symfony/options-resolver/zipball/368128ad168f20e22c32159b9f761e456cec0c78",
+ "reference": "368128ad168f20e22c32159b9f761e456cec0c78",
"shasum": ""
},
"require": {
@@ -3535,7 +3535,7 @@
"options"
],
"support": {
- "source": "https://github.com/symfony/options-resolver/tree/v6.4.13"
+ "source": "https://github.com/symfony/options-resolver/tree/v6.4.16"
},
"funding": [
{
@@ -3551,7 +3551,7 @@
"type": "tidelift"
}
],
- "time": "2024-09-25T14:18:03+00:00"
+ "time": "2024-11-20T10:57:02+00:00"
},
{
"name": "symfony/polyfill-ctype",
@@ -4010,16 +4010,16 @@
},
{
"name": "symfony/service-contracts",
- "version": "v3.5.0",
+ "version": "v3.5.1",
"source": {
"type": "git",
"url": "https://github.com/symfony/service-contracts.git",
- "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f"
+ "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0"
},
"dist": {
"type": "zip",
- "url": "https://api.github.com/repos/symfony/service-contracts/zipball/bd1d9e59a81d8fa4acdcea3f617c581f7475a80f",
- "reference": "bd1d9e59a81d8fa4acdcea3f617c581f7475a80f",
+ "url": "https://api.github.com/repos/symfony/service-contracts/zipball/e53260aabf78fb3d63f8d79d69ece59f80d5eda0",
+ "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0",
"shasum": ""
},
"require": {
@@ -4073,7 +4073,7 @@
"standards"
],
"support": {
- "source": "https://github.com/symfony/service-contracts/tree/v3.5.0"
+ "source": "https://github.com/symfony/service-contracts/tree/v3.5.1"
},
"funding": [
{
@@ -4089,7 +4089,7 @@
"type": "tidelift"
}
],
- "time": "2024-04-18T09:32:20+00:00"
+ "time": "2024-09-25T14:20:29+00:00"
},
{
"name": "symfony/stopwatch",
@@ -4296,7 +4296,7 @@
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
- "php": "~8.1.0 || ~8.2.0 || ~8.3.0",
+ "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0",
"ext-dom": "*",
"ext-gettext": "*",
"ext-simplexml": "*"
diff --git a/doc/en/book.xml b/doc/en/book.xml
index 45fe1aa2..a98b01ef 100644
--- a/doc/en/book.xml
+++ b/doc/en/book.xml
@@ -1383,6 +1383,18 @@ this page has been readed ${page/countRead} times"/>
NE (not equal)
+
+
+ !== :
+ EQQ (strictly equal)
+
+
+
+
+ === :
+ NEE (strictly not equal)
+
+
&& :
diff --git a/rector.php b/rector.php
index f7488e53..7770db97 100644
--- a/rector.php
+++ b/rector.php
@@ -2,10 +2,8 @@
declare(strict_types=1);
-use Rector\CodeQuality\Rector\FuncCall\IntvalToTypeCastRector;
use Rector\Config\RectorConfig;
use Rector\Php55\Rector\String_\StringClassNameToClassConstantRector;
-use Rector\Php73\Rector\FuncCall\JsonThrowOnErrorRector;
use Rector\Php74\Rector\Closure\ClosureToArrowFunctionRector;
use Rector\Php74\Rector\LNumber\AddLiteralSeparatorToNumberRector;
use Rector\Php80\Rector\FunctionLike\MixedTypeRector;
@@ -19,14 +17,12 @@
->withImportNames()
->withSkip([
StringClassNameToClassConstantRector::class,
- JsonThrowOnErrorRector::class,
FirstClassCallableRector::class,
MixedTypeRector::class,
])
->withPhpSets(php81: true)
->withPreparedSets(deadCode: true)
->withRules([
- IntvalToTypeCastRector::class,
AddLiteralSeparatorToNumberRector::class,
ClosureToArrowFunctionRector::class,
]);
diff --git a/src/Context.php b/src/Context.php
index da790811..434ac56a 100644
--- a/src/Context.php
+++ b/src/Context.php
@@ -401,7 +401,7 @@ private static function pathError(mixed $base, string $path, string $current, ?s
*
* @throws Exception\VariableNotFoundException
*/
- public static function path(mixed $base, string $path, bool $nothrow = null): mixed
+ public static function path(mixed $base, string $path, bool $nothrow = false): mixed
{
if ($base === null) {
if ($nothrow) {
diff --git a/src/Dom/Element.php b/src/Dom/Element.php
index b3ab350c..63cefb8c 100644
--- a/src/Dom/Element.php
+++ b/src/Dom/Element.php
@@ -462,7 +462,7 @@ public function generateHead(CodeWriter $codewriter): void
}
}
- public function generateContent(CodeWriter $codewriter, bool $realContent = null): void
+ public function generateContent(CodeWriter $codewriter, bool $realContent = false): void
{
if (!$this->isEmptyNode($codewriter->getOutputMode())) {
if ($realContent || count($this->contentAttributes) === 0) {
diff --git a/src/Dom/SaxXmlParser.php b/src/Dom/SaxXmlParser.php
index 6629261e..787f5fca 100644
--- a/src/Dom/SaxXmlParser.php
+++ b/src/Dom/SaxXmlParser.php
@@ -112,7 +112,7 @@ public function parseFile(DocumentBuilder $builder, string $src): DocumentBuilde
* @throws ParserException
* @throws TemplateException
*/
- public function parseString(DocumentBuilder $builder, string $src, string $filename = null): DocumentBuilder
+ public function parseString(DocumentBuilder $builder, string $src, null|string $filename = null): DocumentBuilder
{
try {
$builder->setEncoding($this->input_encoding);
diff --git a/src/Dom/XmlnsState.php b/src/Dom/XmlnsState.php
index 319137c3..2ab15102 100644
--- a/src/Dom/XmlnsState.php
+++ b/src/Dom/XmlnsState.php
@@ -31,7 +31,7 @@ class XmlnsState
/** Create a new XMLNS state inheriting provided aliases.
* @param array $prefix_to_uri
*/
- public function __construct(private array $prefix_to_uri, private string $current_default)
+ public function __construct(private array $prefix_to_uri, private readonly string $current_default)
{
}
diff --git a/src/NothingKeyword.php b/src/NothingKeyword.php
index 46e983a6..348317e5 100644
--- a/src/NothingKeyword.php
+++ b/src/NothingKeyword.php
@@ -30,9 +30,6 @@ public function count(): int
{
return 0;
}
- /**
- * @return null
- */
public function jsonSerialize(): ?string
{
return null;
diff --git a/src/PHPTAL.php b/src/PHPTAL.php
index 3f2932cc..47f2dc5f 100644
--- a/src/PHPTAL.php
+++ b/src/PHPTAL.php
@@ -256,7 +256,7 @@ public function setTemplate(?string $path): PhpTalInterface
*
* @return $this
*/
- public function setSource(string $src, ?string $path = null): PhpTalInterface
+ public function setSource(string $src, null|string $path = null): PhpTalInterface
{
$this->prepared = false;
$this->functionName = null;
diff --git a/src/Php/CodeWriter.php b/src/Php/CodeWriter.php
index 6291dd85..81a0e3e0 100644
--- a/src/Php/CodeWriter.php
+++ b/src/Php/CodeWriter.php
@@ -179,7 +179,7 @@ public function splitExpression(string $src): array
preg_match_all('/(?:[^;]+|;;)+/sm', $src, $array);
$array = $array[0];
foreach ($array as &$a) {
- $a = str_replace(';;', ';', (string) $a);
+ $a = str_replace(';;', ';', $a);
}
return $array;
}
@@ -270,7 +270,7 @@ public function flushHtml(): void
*
* @param bool $called_from_macro for error checking: unbuffered output doesn't support that
*/
- public function doDoctype(bool $called_from_macro = null): void
+ public function doDoctype(bool $called_from_macro = false): void
{
if ($this->doctype) {
$code = '$ctx->setDocType(' . $this->str($this->doctype) .
@@ -284,7 +284,7 @@ public function doDoctype(bool $called_from_macro = null): void
*
* @param bool $called_from_macro for error checking: unbuffered output doesn't support that
*/
- public function doXmlDeclaration(bool $called_from_macro = null): void
+ public function doXmlDeclaration(bool $called_from_macro = false): void
{
if ($this->xmldeclaration && $this->getOutputMode() !== PHPTAL::HTML5) {
$code = '$ctx->setXmlDeclaration(' . $this->str($this->xmldeclaration) .
@@ -367,7 +367,7 @@ public function doForeach(string $out, string $source): void
/**
* @throws PhpTalException
*/
- public function doEnd(string $expects = null): void
+ public function doEnd(null|string $expects = null): void
{
if (count($this->segments) === 0) {
if ($expects === null) {
diff --git a/src/Php/Transformer.php b/src/Php/Transformer.php
index e5b53b4a..76394124 100644
--- a/src/Php/Transformer.php
+++ b/src/Php/Transformer.php
@@ -55,6 +55,7 @@ class Transformer
private static array $TranslationTable = [
'not' => '!',
'ne' => '!=',
+ 'nee' => '!==',
'and' => '&&',
'or' => '||',
'lt' => '<',
@@ -62,6 +63,7 @@ class Transformer
'ge' => '>=',
'le' => '<=',
'eq' => '==',
+ 'eqq' => '===',
];
/**
diff --git a/src/PhpTalInterface.php b/src/PhpTalInterface.php
index 1238e26d..5f057cfa 100644
--- a/src/PhpTalInterface.php
+++ b/src/PhpTalInterface.php
@@ -28,11 +28,11 @@ public function setTemplate(string $path): self;
* Use setTemplate() or addSourceResolver() whenever possible.
*
* @param string $src The phptal template source.
- * @param string $path Fake and 'unique' template path.
+ * @param null|string $path Fake and 'unique' template path.
*
* @return $this
*/
- public function setSource(string $src, string $path = null): self;
+ public function setSource(string $src, null|string $path = null): self;
/**
* Specify where to look for templates.
diff --git a/tests/PhpModeTestTestCase.php b/tests/PhpModeTest.php
similarity index 96%
rename from tests/PhpModeTestTestCase.php
rename to tests/PhpModeTest.php
index 1c04b48b..7d599654 100644
--- a/tests/PhpModeTestTestCase.php
+++ b/tests/PhpModeTest.php
@@ -22,7 +22,7 @@
use Tests\Testcase\PhpTalTestCase;
use Tests\Testhelper\Helper;
-class PhpModeTestTestCase extends PhpTalTestCase
+class PhpModeTest extends PhpTalTestCase
{
public function tearDown(): void
{
diff --git a/tests/ReadableErrorTest.php b/tests/ReadableErrorTest.php
index 4c679381..4914ecbf 100644
--- a/tests/ReadableErrorTest.php
+++ b/tests/ReadableErrorTest.php
@@ -88,7 +88,7 @@ public function testLocalMacroNotExists(): void
$this->assertThrowsInLine(5, 'input/error-13.html');
}
- public function assertThrowsInLine(int $line, string $file, string $expected_file = null): void
+ public function assertThrowsInLine(int $line, string $file, null|string $expected_file = null): void
{
$tpl = null;
try {
diff --git a/tests/TalesPhpWithReplaceTestTestCase.php b/tests/TalesPhpWithReplaceTest.php
similarity index 95%
rename from tests/TalesPhpWithReplaceTestTestCase.php
rename to tests/TalesPhpWithReplaceTest.php
index 2e76f344..ab938b82 100644
--- a/tests/TalesPhpWithReplaceTestTestCase.php
+++ b/tests/TalesPhpWithReplaceTest.php
@@ -22,7 +22,7 @@
use Tests\Testcase\PhpTalTestCase;
use Tests\Testhelper\Helper;
-class TalesPhpWithReplaceTestTestCase extends PhpTalTestCase
+class TalesPhpWithReplaceTest extends PhpTalTestCase
{
public function testMix(): void
{
diff --git a/tests/Testhelper/CountableImpl.php b/tests/Testhelper/CountableImpl.php
index 355bdadd..58228f97 100644
--- a/tests/Testhelper/CountableImpl.php
+++ b/tests/Testhelper/CountableImpl.php
@@ -24,7 +24,7 @@ class CountableImpl implements Countable
{
private readonly int $cnt;
- public function __construct(int $cnt = null)
+ public function __construct(null|int $cnt = null)
{
$this->cnt = $cnt ?? 0;
}
diff --git a/tests/Testhelper/DummyClass.php b/tests/Testhelper/DummyClass.php
index 7e713e3f..3d9c8f7a 100644
--- a/tests/Testhelper/DummyClass.php
+++ b/tests/Testhelper/DummyClass.php
@@ -20,9 +20,6 @@
class DummyClass
{
- /**
- * @var null
- */
public $foo;
/**
diff --git a/tests/PhpTransformerTestTestCase.php b/tests/TransformerTest.php
similarity index 97%
rename from tests/PhpTransformerTestTestCase.php
rename to tests/TransformerTest.php
index ac3f4552..682676e8 100644
--- a/tests/PhpTransformerTestTestCase.php
+++ b/tests/TransformerTest.php
@@ -22,7 +22,7 @@
use PhpTal\Php\Transformer;
use Tests\Testcase\PhpTalTestCase;
-class PhpTransformerTestTestCase extends PhpTalTestCase
+class TransformerTest extends PhpTalTestCase
{
public function testBooleanOperators(): void
{
@@ -150,6 +150,9 @@ public function testKeywords(): void
{
static::assertSame('true != false', Transformer::transform('true ne false'));
static::assertSame('$test == null', Transformer::transform('test eq null'));
+
+ static::assertSame('true !== false', Transformer::transform('true nee false'));
+ static::assertSame('$test === null', Transformer::transform('test eqq null'));
}
public function testTernaryOperator(): void