Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat: improve type safety with PHPStan (590→0 errors)
Comprehensively resolve all 590 PHPStan errors to improve type safety
and code quality across the entire codebase while maintaining PHP 7.4+
compatibility.
PHPStan: 0 errors (level max + strict rules)

Key improvements:
- Replace elvis operator (?:) with explicit null checks
- Replace empty() with explicit type-safe comparisons
- Add PHPDoc type annotations for better static analysis
- Replace == with === for strict comparisons
- Add null-safety checks for DOM/XPath operations
- Improve type inference for magic properties and dynamic methods
- Add PHP 7.4/8.x compatible type handling (resource vs CurlHandle)

Modified components:
- Core: Embed, Extractor, Document, EmbedCode, etc. (13 files)
- HTTP layer: Crawler, CurlClient, CurlDispatcher (5 files)
- Detectors: All core detectors (17 files)
- Adapters: Archive, Gist, ImageShack, Twitter, Wikipedia, etc. (60 files)
- Data sources: OEmbed, LinkedData, Metas, QueryResult (4 files)
  • Loading branch information
uzulla committed Oct 6, 2025
commit 0e5d3ae60d43a41308e604bb28256f1c7f5e0d08
26 changes: 26 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,29 @@ jobs:

- name: Tests
run: composer test

phpstan:
name: PHPStan Static Analysis
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Install PHP
uses: shivammathur/setup-php@v2
with:
php-version: 8.4

- name: Cache PHP dependencies
uses: actions/cache@v4
with:
path: vendor
key: ${{ runner.os }}-php-8.4-composer-${{ hashFiles('**/composer.json') }}
restore-keys: ${{ runner.os }}-php-8.4-composer-

- name: Install dependencies
run: composer install

- name: Run PHPStan
run: composer phpstan
6 changes: 4 additions & 2 deletions phpstan.dist.neon
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ parameters:
paths:
- src
# - tests
- issue-report/tests
excludePaths:
- tests/cache
- tests/fixtures
checkMissingCallableSignature: true
checkUninitializedProperties: true
checkTooWideReturnTypesInProtectedAndPublicMethods: true
checkImplicitMixed: true
checkImplicitMixed: true
3 changes: 3 additions & 0 deletions src/Adapters/Archive/Api.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ class Api
{
use HttpApiTrait;

/**
* @return array<string, mixed>
*/
protected function fetchData(): array
{
$this->endpoint = $this->extractor->getUri()->withQuery('output=json');
Expand Down
9 changes: 6 additions & 3 deletions src/Adapters/Archive/Detectors/AuthorName.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@

namespace Embed\Adapters\Archive\Detectors;

use Embed\Adapters\Archive\Extractor;
use Embed\Detectors\AuthorName as Detector;

class AuthorName extends Detector
{
public function detect(): ?string
{
$api = $this->extractor->getApi();
/** @var Extractor $extractor */
$extractor = $this->extractor;
$api = $extractor->getApi();

return $api->str('metadata', 'creator')
?: parent::detect();
$result = $api->str('metadata', 'creator');
return $result !== null ? $result : parent::detect();
}
}
9 changes: 6 additions & 3 deletions src/Adapters/Archive/Detectors/Description.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@

namespace Embed\Adapters\Archive\Detectors;

use Embed\Adapters\Archive\Extractor;
use Embed\Detectors\Description as Detector;

class Description extends Detector
{
public function detect(): ?string
{
$api = $this->extractor->getApi();
/** @var Extractor $extractor */
$extractor = $this->extractor;
$api = $extractor->getApi();

return $api->str('metadata', 'extract')
?: parent::detect();
$result = $api->str('metadata', 'extract');
return $result !== null ? $result : parent::detect();
}
}
18 changes: 13 additions & 5 deletions src/Adapters/Archive/Detectors/PublishedTime.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,25 @@
namespace Embed\Adapters\Archive\Detectors;

use DateTime;
use Embed\Adapters\Archive\Extractor;
use Embed\Detectors\PublishedTime as Detector;

class PublishedTime extends Detector
{
public function detect(): ?DateTime
{
$api = $this->extractor->getApi();
/** @var Extractor $extractor */
$extractor = $this->extractor;
$api = $extractor->getApi();

return $api->time('metadata', 'publicdate')
?: $api->time('metadata', 'addeddate')
?: $api->time('metadata', 'date')
?: parent::detect();
$fields = ['publicdate', 'addeddate', 'date'];
foreach ($fields as $field) {
$result = $api->time('metadata', $field);
if ($result !== null) {
return $result;
}
}

return parent::detect();
}
}
9 changes: 6 additions & 3 deletions src/Adapters/Archive/Detectors/Title.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@

namespace Embed\Adapters\Archive\Detectors;

use Embed\Adapters\Archive\Extractor;
use Embed\Detectors\Title as Detector;

class Title extends Detector
{
public function detect(): ?string
{
$api = $this->extractor->getApi();
/** @var Extractor $extractor */
$extractor = $this->extractor;
$api = $extractor->getApi();

return $api->str('metadata', 'title')
?: parent::detect();
$result = $api->str('metadata', 'title');
return $result !== null ? $result : parent::detect();
}
}
10 changes: 7 additions & 3 deletions src/Adapters/Archive/Extractor.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,21 @@

class Extractor extends Base
{
private Api $api;
private ?Api $api = null;

public function getApi(): Api
{
if ($this->api === null) {
$this->api = new Api($this);
}
return $this->api;
}

/**
* @return array<string, \Embed\Detectors\Detector>
*/
public function createCustomDetectors(): array
{
$this->api = new Api($this);

return [
'title' => new Detectors\Title($this),
'description' => new Detectors\Description($this),
Expand Down
3 changes: 3 additions & 0 deletions src/Adapters/Bandcamp/Extractor.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@

class Extractor extends Base
{
/**
* @return array<string, \Embed\Detectors\Detector>
*/
public function createCustomDetectors(): array
{
return [
Expand Down
4 changes: 2 additions & 2 deletions src/Adapters/CadenaSer/Detectors/Code.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ class Code extends Detector
{
public function detect(): ?EmbedCode
{
return parent::detect()
?: $this->fallback();
$result = parent::detect();
return $result !== null ? $result : $this->fallback();
}

private function fallback(): ?EmbedCode
Expand Down
3 changes: 3 additions & 0 deletions src/Adapters/CadenaSer/Extractor.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@

class Extractor extends Base
{
/**
* @return array<string, \Embed\Detectors\Detector>
*/
public function createCustomDetectors(): array
{
return [
Expand Down
4 changes: 2 additions & 2 deletions src/Adapters/Facebook/Detectors/Title.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public function detect(): ?string
$document = $this->extractor->getDocument();
$oembed = $this->extractor->getOEmbed();

return $oembed->str('title')
?: $document->select('.//head/title')->str();
$result = $oembed->str('title');
return $result !== null ? $result : $document->select('.//head/title')->str();
}
}
3 changes: 3 additions & 0 deletions src/Adapters/Facebook/Extractor.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@

class Extractor extends Base
{
/**
* @return array<string, \Embed\Detectors\Detector>
*/
public function createCustomDetectors(): array
{
$this->oembed = new OEmbed($this);
Expand Down
4 changes: 2 additions & 2 deletions src/Adapters/Facebook/OEmbed.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ protected function detectEndpoint(): ?UriInterface
{
$token = $this->extractor->getSetting('facebook:token');

if (!$token) {
if ($token === null || $token === '' || $token === false) {
return null;
}

$uri = $this->extractor->getUri();
if (strpos($uri->getPath(), 'login') !== false) {
parse_str($uri->getQuery(), $params);
if (!empty($params['next'])) {
if (isset($params['next']) && is_string($params['next']) && $params['next'] !== '' && $params['next'] !== '0') {
$uri = $this->extractor->getCrawler()->createUri($params['next']);
}
}
Expand Down
8 changes: 6 additions & 2 deletions src/Adapters/Flickr/Detectors/Code.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@ class Code extends Detector
{
public function detect(): ?EmbedCode
{
return parent::detect()
?: $this->fallback();
$result = parent::detect();
if ($result !== null) {
return $result;
}

return $this->fallback();
}

private function fallback(): ?EmbedCode
Expand Down
3 changes: 3 additions & 0 deletions src/Adapters/Flickr/Extractor.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@

class Extractor extends Base
{
/**
* @return array<string, \Embed\Detectors\Detector>
*/
public function createCustomDetectors(): array
{
return [
Expand Down
3 changes: 3 additions & 0 deletions src/Adapters/Gist/Api.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ class Api
{
use HttpApiTrait;

/**
* @return array<string, mixed>
*/
protected function fetchData(): array
{
$uri = $this->extractor->getUri();
Expand Down
9 changes: 6 additions & 3 deletions src/Adapters/Gist/Detectors/AuthorName.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,18 @@

namespace Embed\Adapters\Gist\Detectors;

use Embed\Adapters\Gist\Extractor;
use Embed\Detectors\AuthorName as Detector;

class AuthorName extends Detector
{
public function detect(): ?string
{
$api = $this->extractor->getApi();
/** @var Extractor $extractor */
$extractor = $this->extractor;
$api = $extractor->getApi();

return $api->str('owner')
?: parent::detect();
$result = $api->str('owner');
return $result !== null ? $result : parent::detect();
}
}
7 changes: 5 additions & 2 deletions src/Adapters/Gist/Detectors/AuthorUrl.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,20 @@

namespace Embed\Adapters\Gist\Detectors;

use Embed\Adapters\Gist\Extractor;
use Embed\Detectors\AuthorUrl as Detector;
use Psr\Http\Message\UriInterface;

class AuthorUrl extends Detector
{
public function detect(): ?UriInterface
{
$api = $this->extractor->getApi();
/** @var Extractor $extractor */
$extractor = $this->extractor;
$api = $extractor->getApi();
$owner = $api->str('owner');

if ($owner) {
if ($owner !== null) {
return $this->extractor->getCrawler()->createUri("https://github.com/{$owner}");
}

Expand Down
13 changes: 9 additions & 4 deletions src/Adapters/Gist/Detectors/Code.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

namespace Embed\Adapters\Gist\Detectors;

use Embed\Adapters\Gist\Extractor;
use Embed\Detectors\Code as Detector;
use Embed\EmbedCode;
use function Embed\html;
Expand All @@ -11,21 +12,25 @@ class Code extends Detector
{
public function detect(): ?EmbedCode
{
return parent::detect()
?: $this->fallback();
$parentResult = parent::detect();
return $parentResult !== null ? $parentResult : $this->fallback();
}

private function fallback(): ?EmbedCode
{
$api = $this->extractor->getApi();
/** @var Extractor $extractor */
$extractor = $this->extractor;
$api = $extractor->getApi();

$code = $api->html('div');
$stylesheet = $api->str('stylesheet');

if ($code && $stylesheet) {
if ($code !== null && $stylesheet !== null) {
return new EmbedCode(
html('link', ['rel' => 'stylesheet', 'href' => $stylesheet]).$code
);
}

return null;
}
}
9 changes: 6 additions & 3 deletions src/Adapters/Gist/Detectors/PublishedTime.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,18 @@
namespace Embed\Adapters\Gist\Detectors;

use DateTime;
use Embed\Adapters\Gist\Extractor;
use Embed\Detectors\PublishedTime as Detector;

class PublishedTime extends Detector
{
public function detect(): ?DateTime
{
$api = $this->extractor->getApi();
/** @var Extractor $extractor */
$extractor = $this->extractor;
$api = $extractor->getApi();

return $api->time('created_at')
?: parent::detect();
$result = $api->time('created_at');
return $result !== null ? $result : parent::detect();
}
}
Loading