On Tue, Mar 25, 2025, at 6:59 AM, Rob Landers wrote: >> When I say module scope, I'm referring to something along the lines that >> Arnaud and I were exploring a while back. tldr, "cluster of files with a >> common namespace root, which can get loaded together." It was mostly about >> performance, but did offer module-private as well, with some nice potential. >> At the moment it's stalled out on "there's nasty hard edge cases and we're >> not sure if it's worth it" concerns. >> >> Concept brain dump here: >> https://github.com/Crell/php-rfcs/blob/master/modules/spec-brainstorm.md >> Code exploration from Arnaud here: >> https://github.com/arnaud-lb/php-src/pull/10 >> >> Still well short of RFC state, of course, but provided for context. > > My email has been broken for a few days, so sorry for the late response...
No worries, I'm about to leave town myself. :-) >> In this case, I am not seeing what the nesting gets you. Making Destination >> a normal class doesn't hurt anything here, does it? > > I wasn't intending to write a definitive example, just to illustrate > it. A better example might be a lazy cache, using hooks to notify the > outer class it has possibly been updated: > > (note this is using the new syntax, but this syntax is NOT currently > reflected in the RFC text, yet) > > namespace Caching; > > class Cache { > private array $items = []; > private array $dirty = []; > > public function getItem(string $key): CacheItem { > return $this->items[$key] ?? ($this->items[$key] = new > CacheItem($this, $key, null)); > } > > public function saveChanges(): void { > foreach ($this->dirty as $key => $value) { > echo "Saving $key to persistent storage\n"; > } > $this->dirty = []; > } > > private function markDirty(string $key): void { > $this->dirty[$key] = $this->items[$key]; > } > > public class CacheItem { > public string|null $value { > get { > return $this->_value; > } > set { > $this->_value = $value; > $this->cache->markDirty($this->key); > } > } > > public function __construct( > private readonly Cache $cache, > public private(set) string $key, > private string|null $_value, > ) {} > } > } > > $cache = new Cache(); > $item1 = $cache->getItem('foo'); > $item1->value = 'bar'; > > $cache->saveChanges(); > > This outputs: > > Saving foo to persistent storage > > This provides for a simple API for outside the Cache class: getItem() > and saveChanges(); that's it. For CacheItem's, you only have the props > for the key or value, and updating the value marks the item as "dirty". > > Currently, if you want this same API, the only way to do this is by: > > 1. using reflection, > 2. using a closure and binding it to the other class's scope, > 3. providing a listener + observer (more formal version of [2]), or > 3. iterating over items while saving to find dirty items. > > Those choices are not ideal (IMHO). > > Reflection feels "hacky" as does using a bound closure. The > listener/observer pattern is probably overkill here, unless you already > have one lying around (i.e., using symfony/laravel or a related > framework), but still might require making some of the "internal" api > public. Finally, iterating over all the items to find dirty ones is > naive and inefficient. > > Hopefully this is a better illustration of what nesting provides? > > -- Rob I have a similar if less involved use case in my ordering library, though it doesn't need the look-back functionality. So the use case that nested classes would enable that isn't currently covered by "just use separate files and @internal, deal" is around the lesser class having private access to the greater class. Which... I believe fileprivate and modules would also address, albeit in a different way, yes? (Presuming fileprivate is available on properties, not just the class itself.) --Larry Garfield