TLDR
The Drupal\Core\Extension\Extension uses magic __call() to pretend that it is also the extension file.
This muddles concerns that should be separate, and makes the class more complex than it needs to be.
An extension is not conceptually identical with its *.info.yml file.
Current situation
The class Drupal\Core\Extension\Extension was introduced in #2188661: Extension System, Part II: ExtensionDiscovery.
It contains one method Extension::__call(), which re-routes calls to SplFileInfo.
/**
* Re-routes method calls to SplFileInfo.
*
* Offers all SplFileInfo methods to consumers; e.g., $extension->getMTime().
*/
public function __call($method, array $args) {
if (!isset($this->splFileInfo)) {
$this->splFileInfo = new \SplFileInfo($this->pathname);
}
return call_user_func_array([$this->splFileInfo, $method], $args);
}
I claim that this is a bad idea.
As a reader, one immediately wonders: Which parts of \SplFileInfo do we actually want to expose?
How can I find usages of those methods? The IDE won't help, because it's all magic.
We could declare the implicit methods as @method tags.
I did this locally, and my IDE tells me that 2 of those are actually used, 22 are not used, and 4 are overwritten by an explicit implementation.
namespace Drupal\Core\Extension;
/**
* Defines an extension (file) object.
*
* Used:
* @method getMTime()
* @method getCTime()
*
* Overwritten by explicit method (IDE complains):
* @method getPath()
* @method getFilename()
* @method getPathname()
* @method getType() - meaning changed.
*
* Not used:
* @method getExtension()
* @method getBasename()
* @method getPerms()
* @method getInode()
* @method getSize()
* @method getOwner()
* @method getGroup()
* @method getATime()
* @method isWritable()
* @method isReadable()
* @method isExecutable()
* @method isFile()
* @method isDir()
* @method isLink()
* @method getLinkTarget()
* @method getRealPath()
* @method getFileInfo()
* @method getPathInfo()
* @method openFile()
* @method setFileClass()
* @method setInfoClass()
* @method __toString()
*/
class Extension implements \Serializable {
Problems
The added magic method Extension::__call() adds potential complexity to the class, only so that a few places of consumer code can get the mtime and the ctime of the file.
It also pretends that the extension is identical with the file, which it shouldn't be.
It also introduces a huge BC commitment, if we consider the entire SplFileInfo as part of the public API of the class Extension.
I am sure there were reasons for this, but that doesn't mean it was a good idea, or inevitable.
Solution
- Add a method Extension::getFileInfo() to get the SplFileInfo of the *.info.yml file.
- Deprecate the magic Extension::__call() for removal in Drupal 11
This won't require major changes in core, and contrib could still work as it is for now.
| Comment | File | Size | Author |
|---|---|---|---|
| #30 | 2959989-30.patch | 4.9 KB | andypost |
| #30 | interdiff.txt | 642 bytes | andypost |
Comments
Comment #11
andypostNow this method caused phpstan to fail so changing to bug, see https://www.drupal.org/pift-ci-job/2520505 and #3015812-112: Introduce new Theme extension object and properly deprecate REGIONS_VISIBLE and REGIONS_ALL
Solution could be add annotation as the issue doing or provide some method to return iterator
Comment #12
andypostThe usage is not that big
Comment #13
geek-merlinWe have a well-proven deprecation workflow, so +1 for the clean solution option 1, to add getSplFileInfo (we can bikeshed on the method name) and deprecate __call.
Comment #14
andypostLet's see if there's a any other calls to it
Comment #16
andypostand debug information
Comment #17
andypostvalid patch
Comment #19
andypostSo only
getMTime()used once in runtime and once in api docsgetCTime()used once in runtimeComment #20
andypostwe can deprecate this key as it is not parsed see \Drupal\Core\Utility\ProjectInfo::filterProjectInfo() and used only by tests
consumed only by locale and update modules
Comment #21
andypost- 4 usages in contrib http://codcontrib.hank.vps-private.net/search?text=_info_file_ctime&file...
- 2 usages http://codcontrib.hank.vps-private.net/search?text=%27mtime%27&filename=
Comment #22
geek-merlinHey, that ended up simple!
Code looks straightforward and tests are green.
Added a draft CR.
Added followup for #20.
Deeming RTBC.
Comment #23
andypostNeeds to fix link to real cr and add tests somehow
Comment #24
avpadernoComment #25
andypostFixed link to CR and added deprecation test, now looks ready
IS needs to be fixed because I'm using more generic name
getFileInfo()instead of mentioning implementation details of SPL (which could be a cause of naming issue for caps/no-caps)Comment #26
spokjeSad TestBot :(
Comment #27
andypostfix c/p error
Comment #28
feuerwagenTestbot is green, test looks good. Also updated the IS.
Comment #29
alexpottMissing @return documentation. I think we should still have this - unless we've changed our coding standards.
Comment #30
andypostThanks, added
Comment #31
alexpottMarking as RTBC as the only changes here are comments. Thanks @andypost.
Comment #32
alexpottCommitted 5b8e018 and pushed to 10.1.x. Thanks!