From 27be0e7157333887136b9e02303c263065a7246b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A1rk=20Magyar?= <14284867+xHeaven@users.noreply.github.com> Date: Wed, 7 Jun 2023 16:47:52 +0200 Subject: [PATCH] code refactor (#364) * use spread syntax instead of array_merge() * use type cast instead of function cast * removed redundant returns * removed redundant phpdoc - type is already inferred * removed invalid phpdoc - type is already inferred The PHPDoc return type hint was incomplete, it should have been `InvalidEmail|null`, however, it can be removed altogether as the return type is already inferred from the code. * changed warnEscaping()'s return value from bool to void This is not a breaking change as the method is private, and it's only used at one place, where the return value was not used anyway. * made private class property local `private $parser` was used in only one place, hence it can be local, there is no reason to put it into the class' scope. * removed unnecessary type casting Concatenation already casts `static::CODE` from `int` to `string`, no reason to do it explicitly. * removed redundant initializers - constructor overwrites them immediately * removed redundant else block * simplified if-else statement * wrapped if body in brackets to comply with PSR12 * fixed README formatting - fixed numbering at the `Available validations` section - fixed overall formatting * Revert "removed redundant phpdoc - type is already inferred" This reverts commit 68a9ae20bd69aeb3e252ff7b581d85e0012d42ca. * don't wrap long lines * make properties typed Also using constructor property promotion, see more info about it [here](https://php.watch/versions/8.0/constructor-property-promotion). --- README.md | 38 +++++++++---------- src/EmailParser.php | 4 +- src/MessageIDParser.php | 4 +- src/Parser/Comment.php | 11 +++--- src/Parser/CommentStrategy/DomainComment.php | 6 +-- src/Parser/DomainLiteral.php | 4 +- src/Parser/DomainPart.php | 12 +++--- src/Parser/DoubleQuote.php | 8 +++- src/Parser/LocalPart.php | 14 ++----- src/Parser/PartParser.php | 2 +- src/Result/Reason/UnusualElements.php | 2 +- src/Validation/DNSRecords.php | 15 +------- src/Validation/Extra/SpoofCheckValidation.php | 3 -- src/Validation/MultipleValidationWithAnd.php | 17 +-------- src/Validation/RFCValidation.php | 11 ++---- src/Warning/Warning.php | 2 +- 16 files changed, 56 insertions(+), 97 deletions(-) diff --git a/README.md b/README.md index bdcb35d3..a5294b90 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ A library for validating emails against several RFC. -## Supported RFCs ## +## Supported RFCs This library aims to support RFCs: @@ -21,15 +21,15 @@ This library aims to support RFCs: **Current major version with full support is v3** -| Version | Released | EOL | Only critical bug fixes | Full | -| :-----: | :--------: | :---: | :---------------------: | :---: | -| v4.x | 2023/01/07 | - | X | X | -| v3.x | 2020/12/29 | - | X | | -| v2.1.x | 2016/05/16 | YES | | | -| v1.2 | 2013/19/05 | YES | | | +| Version | Released | EOL | Only critical bug fixes | Full | +|:-------:|:----------:|:---:|:-----------------------:|:----:| +| v4.x | 2023/01/07 | - | X | X | +| v3.x | 2020/12/29 | - | X | | +| v2.1.x | 2016/05/16 | YES | | | +| v1.2 | 2013/19/05 | YES | | | -## Requirements ## +## Requirements * PHP 8.1 * [Composer](https://getcomposer.org) is required for installation @@ -37,7 +37,7 @@ This library aims to support RFCs: **Note**: `PHP version upgrades will happen to accomodate to the pace of major frameworks. Minor versions bumps will go via minor versions of this library (i.e: PHP7.3 -> v3.x+1). Major versions will go with major versions of the library` -## Installation ## +## Installation Run the command below to install via Composer @@ -45,7 +45,7 @@ Run the command below to install via Composer composer require egulias/email-validator ``` -## Getting Started ## +## Getting Started `EmailValidator` requires you to decide which (or combination of them) validation/s strategy/ies you'd like to follow for each [validation](#available-validations). @@ -61,14 +61,14 @@ $validator->isValid("example@example.com", new RFCValidation()); //true ``` -### Available validations ### +### Available validations 1. [RFCValidation](/src/Validation/RFCValidation.php): Standard RFC-like email validation. 2. [NoRFCWarningsValidation](/src/Validation/NoRFCWarningsValidation.php): RFC-like validation that will fail when warnings* are found. 3. [DNSCheckValidation](/src/Validation/DNSCheckValidation.php): Will check if there are DNS records that signal that the server accepts emails. This does not entail that the email exists. -5. [MultipleValidationWithAnd](/src/Validation/MultipleValidationWithAnd.php): It is a validation that operates over other validations performing a logical and (&&) over the result of each validation. -6. [MessageIDValidation](/src/Validation/MessageIDValidation.php): Follows [RFC2822 for message-id](https://tools.ietf.org/html/rfc2822#section-3.6.4) to validate that field, that has some differences in the domain part. -7. [Your own validation](#how-to-extend): You can extend the library behaviour by implementing your own validations. +4. [MultipleValidationWithAnd](/src/Validation/MultipleValidationWithAnd.php): It is a validation that operates over other validations performing a logical and (&&) over the result of each validation. +5. [MessageIDValidation](/src/Validation/MessageIDValidation.php): Follows [RFC2822 for message-id](https://tools.ietf.org/html/rfc2822#section-3.6.4) to validate that field, that has some differences in the domain part. +6. [Your own validation](#how-to-extend): You can extend the library behaviour by implementing your own validations. *warnings: Warnings are deviations from the RFC that in a broader interpretation are accepted. @@ -89,21 +89,21 @@ $multipleValidations = new MultipleValidationWithAnd([ $validator->isValid("example@ietf.org", $multipleValidations); //true ``` -#### Additional validations #### +#### Additional validations Validations not present in the RFCs 1. [SpoofCheckValidation](/src/Validation/Extra/SpoofCheckValidation.php): Will check for multi-utf-8 chars that can signal an erroneous email name. -### How to extend ### +### How to extend It's easy! You just need to implement [EmailValidation](/src/Validation/EmailValidation.php) and you can use your own validation. -## Contributing ## +## Contributing Please follow the [Contribution guide](CONTRIBUTING.md). Is short and simple and will help a lot. -## Other Contributors ## +## Other Contributors (You can find current contributors [here](https://github.com/egulias/EmailValidator/graphs/contributors)) @@ -113,6 +113,6 @@ As this is a port from another library and work, here are other people related t * Josepf Bielawski [@stloyd](https://github.com/stloyd): For its first re-work of Dominic's lib * Dominic Sayers [@dominicsayers](https://github.com/dominicsayers): The original isemail function -## License ## +## License Released under the MIT License attached with this code. diff --git a/src/EmailParser.php b/src/EmailParser.php index 788d016e..fc449c76 100644 --- a/src/EmailParser.php +++ b/src/EmailParser.php @@ -56,7 +56,7 @@ private function processLocalPart(): Result $localPartParser = new LocalPart($this->lexer); $localPartResult = $localPartParser->parse(); $this->localPart = $localPartParser->localPart(); - $this->warnings = array_merge($localPartParser->getWarnings(), $this->warnings); + $this->warnings = [...$localPartParser->getWarnings(), ...$this->warnings]; return $localPartResult; } @@ -66,7 +66,7 @@ private function processDomainPart(): Result $domainPartParser = new DomainPart($this->lexer); $domainPartResult = $domainPartParser->parse(); $this->domainPart = $domainPartParser->domainPart(); - $this->warnings = array_merge($domainPartParser->getWarnings(), $this->warnings); + $this->warnings = [...$domainPartParser->getWarnings(), ...$this->warnings]; return $domainPartResult; } diff --git a/src/MessageIDParser.php b/src/MessageIDParser.php index 9df27dba..35bd0a7f 100644 --- a/src/MessageIDParser.php +++ b/src/MessageIDParser.php @@ -57,7 +57,7 @@ private function processIDLeft(): Result $localPartParser = new IDLeftPart($this->lexer); $localPartResult = $localPartParser->parse(); $this->idLeft = $localPartParser->localPart(); - $this->warnings = array_merge($localPartParser->getWarnings(), $this->warnings); + $this->warnings = [...$localPartParser->getWarnings(), ...$this->warnings]; return $localPartResult; } @@ -67,7 +67,7 @@ private function processIDRight(): Result $domainPartParser = new IDRightPart($this->lexer); $domainPartResult = $domainPartParser->parse(); $this->idRight = $domainPartParser->domainPart(); - $this->warnings = array_merge($domainPartParser->getWarnings(), $this->warnings); + $this->warnings = [...$domainPartParser->getWarnings(), ...$this->warnings]; return $domainPartResult; } diff --git a/src/Parser/Comment.php b/src/Parser/Comment.php index 9e4ab218..7b5b47e2 100644 --- a/src/Parser/Comment.php +++ b/src/Parser/Comment.php @@ -66,29 +66,28 @@ public function parse(): Result $finalValidations = $this->commentStrategy->endOfLoopValidations($this->lexer); - $this->warnings = array_merge($this->warnings, $this->commentStrategy->getWarnings()); + $this->warnings = [...$this->warnings, ...$this->commentStrategy->getWarnings()]; return $finalValidations; } /** - * @return bool + * @return void */ - private function warnEscaping(): bool + private function warnEscaping(): void { //Backslash found if (!$this->lexer->current->isA(EmailLexer::S_BACKSLASH)) { - return false; + return; } if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB, EmailLexer::C_DEL))) { - return false; + return; } $this->warnings[QuotedPart::CODE] = new QuotedPart($this->lexer->getPrevious()->type, $this->lexer->current->type); - return true; } private function noClosingParenthesis(): bool diff --git a/src/Parser/CommentStrategy/DomainComment.php b/src/Parser/CommentStrategy/DomainComment.php index a197c270..80d6d104 100644 --- a/src/Parser/CommentStrategy/DomainComment.php +++ b/src/Parser/CommentStrategy/DomainComment.php @@ -12,11 +12,7 @@ class DomainComment implements CommentStrategy { public function exitCondition(EmailLexer $lexer, int $openedParenthesis): bool { - if (($openedParenthesis === 0 && $lexer->isNextToken(EmailLexer::S_DOT))) { // || !$internalLexer->moveNext()) { - return false; - } - - return true; + return !($openedParenthesis === 0 && $lexer->isNextToken(EmailLexer::S_DOT)); } public function endOfLoopValidations(EmailLexer $lexer): Result diff --git a/src/Parser/DomainLiteral.php b/src/Parser/DomainLiteral.php index e99498d2..5093e508 100644 --- a/src/Parser/DomainLiteral.php +++ b/src/Parser/DomainLiteral.php @@ -82,10 +82,10 @@ public function parse(): Result if (!$isAddressLiteralIPv4) { return new ValidEmail(); - } else { - $addressLiteral = $this->convertIPv4ToIPv6($addressLiteral); } + $addressLiteral = $this->convertIPv4ToIPv6($addressLiteral); + if (!$IPv6TAG) { $this->warnings[WarningDomainLiteral::CODE] = new WarningDomainLiteral(); return new ValidEmail(); diff --git a/src/Parser/DomainPart.php b/src/Parser/DomainPart.php index 6aca5373..a1a56cf3 100644 --- a/src/Parser/DomainPart.php +++ b/src/Parser/DomainPart.php @@ -137,7 +137,7 @@ protected function parseComments(): Result { $commentParser = new Comment($this->lexer, new DomainComment()); $result = $commentParser->parse(); - $this->warnings = array_merge($this->warnings, $commentParser->getWarnings()); + $this->warnings = [...$this->warnings, ...$commentParser->getWarnings()]; return $result; } @@ -213,9 +213,9 @@ protected function doParseDomainPart(): Result return new ValidEmail(); } - /** + /** * @param Token $token - * + * * @return Result */ private function checkNotAllowedChars(Token $token): Result @@ -240,14 +240,14 @@ protected function parseDomainLiteral(): Result $domainLiteralParser = new DomainLiteralParser($this->lexer); $result = $domainLiteralParser->parse(); - $this->warnings = array_merge($this->warnings, $domainLiteralParser->getWarnings()); + $this->warnings = [...$this->warnings, ...$domainLiteralParser->getWarnings()]; return $result; } /** * @param Token $prev * @param bool $hasComments - * + * * @return Result */ protected function checkDomainPartExceptions(Token $prev, bool $hasComments): Result @@ -323,4 +323,4 @@ public function domainPart(): string { return $this->domainPart; } -} \ No newline at end of file +} diff --git a/src/Parser/DoubleQuote.php b/src/Parser/DoubleQuote.php index b96dba50..b5335d30 100644 --- a/src/Parser/DoubleQuote.php +++ b/src/Parser/DoubleQuote.php @@ -17,7 +17,9 @@ public function parse(): Result { $validQuotedString = $this->checkDQUOTE(); - if ($validQuotedString->isInvalid()) return $validQuotedString; + if ($validQuotedString->isInvalid()) { + return $validQuotedString; + } $special = [ EmailLexer::S_CR => true, @@ -56,7 +58,9 @@ public function parse(): Result if ($prev->isA(EmailLexer::S_BACKSLASH)) { $validQuotedString = $this->checkDQUOTE(); - if ($validQuotedString->isInvalid()) return $validQuotedString; + if ($validQuotedString->isInvalid()) { + return $validQuotedString; + } } if (!$this->lexer->isNextToken(EmailLexer::S_AT) && !$prev->isA(EmailLexer::S_BACKSLASH)) { diff --git a/src/Parser/LocalPart.php b/src/Parser/LocalPart.php index a6087e62..5ed29d60 100644 --- a/src/Parser/LocalPart.php +++ b/src/Parser/LocalPart.php @@ -118,7 +118,7 @@ private function parseLocalFWS(): Result $foldingWS = new FoldingWhiteSpace($this->lexer); $resultFWS = $foldingWS->parse(); if ($resultFWS->isValid()) { - $this->warnings = array_merge($this->warnings, $foldingWS->getWarnings()); + $this->warnings = [...$this->warnings, ...$foldingWS->getWarnings()]; } return $resultFWS; } @@ -132,7 +132,7 @@ private function parseDoubleQuote(): Result { $dquoteParser = new DoubleQuote($this->lexer); $parseAgain = $dquoteParser->parse(); - $this->warnings = array_merge($this->warnings, $dquoteParser->getWarnings()); + $this->warnings = [...$this->warnings, ...$dquoteParser->getWarnings()]; return $parseAgain; } @@ -141,10 +141,8 @@ protected function parseComments(): Result { $commentParser = new Comment($this->lexer, new LocalComment()); $result = $commentParser->parse(); - $this->warnings = array_merge($this->warnings, $commentParser->getWarnings()); - if ($result->isInvalid()) { - return $result; - } + $this->warnings = [...$this->warnings, ...$commentParser->getWarnings()]; + return $result; } @@ -159,10 +157,6 @@ private function validateEscaping(): Result return new InvalidEmail(new ExpectingATEXT('Found ATOM after escaping'), $this->lexer->current->value); } - if (!$this->lexer->isNextTokenAny(array(EmailLexer::S_SP, EmailLexer::S_HTAB, EmailLexer::C_DEL))) { - return new ValidEmail(); - } - return new ValidEmail(); } } diff --git a/src/Parser/PartParser.php b/src/Parser/PartParser.php index d0ed5fd7..53afb257 100644 --- a/src/Parser/PartParser.php +++ b/src/Parser/PartParser.php @@ -40,7 +40,7 @@ protected function parseFWS(): Result { $foldingWS = new FoldingWhiteSpace($this->lexer); $resultFWS = $foldingWS->parse(); - $this->warnings = array_merge($this->warnings, $foldingWS->getWarnings()); + $this->warnings = [...$this->warnings, ...$foldingWS->getWarnings()]; return $resultFWS; } diff --git a/src/Result/Reason/UnusualElements.php b/src/Result/Reason/UnusualElements.php index 861f3bcb..18b6e6e1 100644 --- a/src/Result/Reason/UnusualElements.php +++ b/src/Result/Reason/UnusualElements.php @@ -7,7 +7,7 @@ class UnusualElements implements Reason /** * @var string $element */ - private $element = ''; + private $element; public function __construct(string $element) { diff --git a/src/Validation/DNSRecords.php b/src/Validation/DNSRecords.php index 3a9915dc..3f775f06 100644 --- a/src/Validation/DNSRecords.php +++ b/src/Validation/DNSRecords.php @@ -4,25 +4,12 @@ class DNSRecords { - - /** - * @var array $records - */ - private $records = []; - - /** - * @var bool $error - */ - private $error = false; - /** * @param array $records * @param bool $error */ - public function __construct(array $records, bool $error = false) + public function __construct(private readonly array $records, private readonly bool $error = false) { - $this->records = $records; - $this->error = $error; } /** diff --git a/src/Validation/Extra/SpoofCheckValidation.php b/src/Validation/Extra/SpoofCheckValidation.php index 4972dbce..463cafd4 100644 --- a/src/Validation/Extra/SpoofCheckValidation.php +++ b/src/Validation/Extra/SpoofCheckValidation.php @@ -37,9 +37,6 @@ public function isValid(string $email, EmailLexer $emailLexer) : bool return $this->error === null; } - /** - * @return InvalidEmail - */ public function getError() : ?InvalidEmail { return $this->error; diff --git a/src/Validation/MultipleValidationWithAnd.php b/src/Validation/MultipleValidationWithAnd.php index f23e84b5..c908053f 100644 --- a/src/Validation/MultipleValidationWithAnd.php +++ b/src/Validation/MultipleValidationWithAnd.php @@ -22,11 +22,6 @@ class MultipleValidationWithAnd implements EmailValidation */ public const ALLOW_ALL_ERRORS = 1; - /** - * @var EmailValidation[] - */ - private $validations = []; - /** * @var Warning[] */ @@ -37,23 +32,15 @@ class MultipleValidationWithAnd implements EmailValidation */ private $error; - /** - * @var int - */ - private $mode; - /** * @param EmailValidation[] $validations The validations. * @param int $mode The validation mode (one of the constants). */ - public function __construct(array $validations, $mode = self::ALLOW_ALL_ERRORS) + public function __construct(private readonly array $validations, private readonly int $mode = self::ALLOW_ALL_ERRORS) { if (count($validations) == 0) { throw new EmptyValidationList(); } - - $this->validations = $validations; - $this->mode = $mode; } /** @@ -66,7 +53,7 @@ public function isValid(string $email, EmailLexer $emailLexer): bool $emailLexer->reset(); $validationResult = $validation->isValid($email, $emailLexer); $result = $result && $validationResult; - $this->warnings = array_merge($this->warnings, $validation->getWarnings()); + $this->warnings = [...$this->warnings, ...$validation->getWarnings()]; if (!$validationResult) { $this->processError($validation); } diff --git a/src/Validation/RFCValidation.php b/src/Validation/RFCValidation.php index f5819d83..f59cbfc8 100644 --- a/src/Validation/RFCValidation.php +++ b/src/Validation/RFCValidation.php @@ -10,11 +10,6 @@ class RFCValidation implements EmailValidation { - /** - * @var EmailParser|null - */ - private $parser; - /** * @var Warning[] */ @@ -27,10 +22,10 @@ class RFCValidation implements EmailValidation public function isValid(string $email, EmailLexer $emailLexer): bool { - $this->parser = new EmailParser($emailLexer); + $parser = new EmailParser($emailLexer); try { - $result = $this->parser->parse($email); - $this->warnings = $this->parser->getWarnings(); + $result = $parser->parse($email); + $this->warnings = $parser->getWarnings(); if ($result->isInvalid()) { /** @psalm-suppress PropertyTypeCoercion */ $this->error = $result; diff --git a/src/Warning/Warning.php b/src/Warning/Warning.php index e5b6ad8e..7adb3b85 100644 --- a/src/Warning/Warning.php +++ b/src/Warning/Warning.php @@ -48,6 +48,6 @@ public function RFCNumber() */ public function __toString(): string { - return $this->message() . " rfc: " . $this->rfcNumber . "internal code: " . strval(static::CODE); + return $this->message() . " rfc: " . $this->rfcNumber . "internal code: " . static::CODE; } }