From e17507c5d78da57f94c1d35b587687f787231ca8 Mon Sep 17 00:00:00 2001
From: Lonny Kapelushnik <lonny@lonnylot.com>
Date: Thu, 25 Apr 2024 22:32:38 -0600
Subject: [PATCH 1/2] Additional performance improvements

---
 src/Illuminate/Events/Dispatcher.php          | 19 +++++++-
 src/Illuminate/View/AnonymousComponent.php    | 26 ++++++++++-
 src/Illuminate/View/Compilers/Compiler.php    |  9 +++-
 .../View/Compilers/ComponentTagCompiler.php   | 15 +++++--
 .../View/Concerns/ManagesComponents.php       |  6 ++-
 src/Illuminate/View/Factory.php               | 45 ++++++++++++++++---
 src/Illuminate/View/View.php                  |  6 +--
 7 files changed, 110 insertions(+), 16 deletions(-)

diff --git a/src/Illuminate/Events/Dispatcher.php b/src/Illuminate/Events/Dispatcher.php
index c418fc4d06b8..a43a76aec0a8 100755
--- a/src/Illuminate/Events/Dispatcher.php
+++ b/src/Illuminate/Events/Dispatcher.php
@@ -66,6 +66,13 @@ class Dispatcher implements DispatcherContract
      */
     protected $transactionManagerResolver;
 
+    /**
+     * The cache of events that have listeners.
+     *
+     * @var array
+     */
+    protected $listenerCache = [];
+
     /**
      * Create a new event dispatcher instance.
      *
@@ -107,6 +114,8 @@ public function listen($events, $listener = null)
                 $this->listeners[$event][] = $listener;
             }
         }
+
+        $this->listenerCache = [];
     }
 
     /**
@@ -131,9 +140,15 @@ protected function setupWildcardListen($event, $listener)
      */
     public function hasListeners($eventName)
     {
-        return isset($this->listeners[$eventName]) ||
+        if (isset($this->listenerCache[$eventName])) {
+            return $this->listenerCache[$eventName];
+        }
+
+        $this->listenerCache[$eventName] = isset($this->listeners[$eventName]) ||
                isset($this->wildcards[$eventName]) ||
                $this->hasWildcardListeners($eventName);
+
+        return $this->listenerCache[$eventName];
     }
 
     /**
@@ -703,6 +718,8 @@ public function forget($event)
                 unset($this->wildcardsCache[$key]);
             }
         }
+
+        $this->listenerCache = [];
     }
 
     /**
diff --git a/src/Illuminate/View/AnonymousComponent.php b/src/Illuminate/View/AnonymousComponent.php
index eba64365626b..3cb1c1783974 100644
--- a/src/Illuminate/View/AnonymousComponent.php
+++ b/src/Illuminate/View/AnonymousComponent.php
@@ -25,10 +25,11 @@ class AnonymousComponent extends Component
      * @param  array  $data
      * @return void
      */
-    public function __construct($view, $data)
+    public function __construct($view, $data, Factory $factory)
     {
         $this->view = $view;
         $this->data = $data;
+        self::$factory = $factory;
     }
 
     /**
@@ -41,6 +42,29 @@ public function render()
         return $this->view;
     }
 
+    /**
+     * Resolve the component instance with the given data.
+     *
+     * @param  array  $data
+     * @return static
+     */
+    public static function resolve($data)
+    {
+        return new static(...$data);
+    }
+
+    /**
+     * Resolve the Blade view or view file that should be used when rendering the component.
+     *
+     * @return string
+     */
+    public function resolveView()
+    {
+        $view = $this->render();
+
+        return $this->extractBladeViewFromString($view);
+    }
+
     /**
      * Get the data that should be supplied to the view.
      *
diff --git a/src/Illuminate/View/Compilers/Compiler.php b/src/Illuminate/View/Compilers/Compiler.php
index 7ec15ac96f74..f1febb6c9727 100755
--- a/src/Illuminate/View/Compilers/Compiler.php
+++ b/src/Illuminate/View/Compilers/Compiler.php
@@ -44,6 +44,13 @@ abstract class Compiler
      */
     protected $compiledExtension = 'php';
 
+    /**
+     * The cache of compiled paths.
+     *
+     * @var array
+     */
+    protected $compiledPathCache = [];
+
     /**
      * Create a new compiler instance.
      *
@@ -82,7 +89,7 @@ public function __construct(
      */
     public function getCompiledPath($path)
     {
-        return $this->cachePath.'/'.hash('xxh128', 'v2'.Str::after($path, $this->basePath)).'.'.$this->compiledExtension;
+        return $this->compiledPathCache[$path] ??= $this->cachePath.'/'.hash('xxh128', 'v2'.Str::after($path, $this->basePath)).'.'.$this->compiledExtension;
     }
 
     /**
diff --git a/src/Illuminate/View/Compilers/ComponentTagCompiler.php b/src/Illuminate/View/Compilers/ComponentTagCompiler.php
index 9c3d6adbec99..c726f3fb8e98 100644
--- a/src/Illuminate/View/Compilers/ComponentTagCompiler.php
+++ b/src/Illuminate/View/Compilers/ComponentTagCompiler.php
@@ -251,6 +251,7 @@ protected function componentString(string $component, array $attributes)
             $parameters = [
                 'view' => $view,
                 'data' => '['.$this->attributesToString($data->all(), $escapeBound = false).']',
+                'factory' => '$__env',
             ];
 
             $class = AnonymousComponent::class;
@@ -776,9 +777,17 @@ protected function attributesToString(array $attributes, $escapeBound = true)
     {
         return collect($attributes)
                 ->map(function (string $value, string $attribute) use ($escapeBound) {
-                    return $escapeBound && isset($this->boundAttributes[$attribute]) && $value !== 'true' && ! is_numeric($value)
-                                ? "'{$attribute}' => \Illuminate\View\Compilers\BladeCompiler::sanitizeComponentAttribute({$value})"
-                                : "'{$attribute}' => {$value}";
+                    $shouldSanitize = $escapeBound && isset($this->boundAttributes[$attribute]) && $value !== 'true' && ! is_numeric($value);
+
+                    if ($shouldSanitize) {
+                        $value = \Illuminate\View\Compilers\BladeCompiler::sanitizeComponentAttribute($value);
+
+                        if (is_string($value)) {
+                            return "'{$attribute}' => '{$value}'";
+                        }
+                    }
+
+                    return "'{$attribute}' => {$value}";
                 })
                 ->implode(',');
     }
diff --git a/src/Illuminate/View/Concerns/ManagesComponents.php b/src/Illuminate/View/Concerns/ManagesComponents.php
index 456e6a044e5d..ab6fc54fb474 100644
--- a/src/Illuminate/View/Concerns/ManagesComponents.php
+++ b/src/Illuminate/View/Concerns/ManagesComponents.php
@@ -56,9 +56,11 @@ public function startComponent($view, array $data = [])
         if (ob_start()) {
             $this->componentStack[] = $view;
 
-            $this->componentData[$this->currentComponent()] = $data;
+            $currentComponent = $this->currentComponent();
 
-            $this->slots[$this->currentComponent()] = [];
+            $this->componentData[$currentComponent] = $data;
+
+            $this->slots[$currentComponent] = [];
         }
     }
 
diff --git a/src/Illuminate/View/Factory.php b/src/Illuminate/View/Factory.php
index bc6e59d55afd..2db93d8cdd01 100755
--- a/src/Illuminate/View/Factory.php
+++ b/src/Illuminate/View/Factory.php
@@ -2,14 +2,15 @@
 
 namespace Illuminate\View;
 
-use Illuminate\Contracts\Container\Container;
-use Illuminate\Contracts\Events\Dispatcher;
-use Illuminate\Contracts\Support\Arrayable;
-use Illuminate\Contracts\View\Factory as FactoryContract;
 use Illuminate\Support\Arr;
+use InvalidArgumentException;
 use Illuminate\Support\Traits\Macroable;
+use Illuminate\Contracts\Events\Dispatcher;
+use Illuminate\Contracts\Support\Arrayable;
 use Illuminate\View\Engines\EngineResolver;
-use InvalidArgumentException;
+use Illuminate\Contracts\Support\Renderable;
+use Illuminate\Contracts\Container\Container;
+use Illuminate\Contracts\View\Factory as FactoryContract;
 
 class Factory implements FactoryContract
 {
@@ -104,6 +105,20 @@ class Factory implements FactoryContract
      */
     protected $normalizedNameCache = [];
 
+    /**
+     * Flag to determine if renderable shared data cache is set.
+     *
+     * @var boolean
+     */
+    protected $renderableSharedCacheIsSet = false;
+
+    /**
+     * The cache of shared data with objects cast to strings.
+     *
+     * @var array
+     */
+    protected $renderableSharedCache = [];
+
     /**
      * Create a new view factory instance.
      *
@@ -358,6 +373,8 @@ public function share($key, $value = null)
             $this->shared[$key] = $value;
         }
 
+        $this->renderableSharedCacheIsSet = false;
+
         return $value;
     }
 
@@ -631,4 +648,22 @@ public function getShared()
     {
         return $this->shared;
     }
+
+    public function getRenderableShared()
+    {
+        if ($this->renderableSharedCacheIsSet) {
+            return $this->renderableSharedCache;
+        }
+
+        $this->renderableSharedCache = $this->getShared();
+        foreach ($this->renderableSharedCache as $key => $value) {
+            if ($value instanceof Renderable) {
+                $this->renderableSharedCache[$key] = $value->render();
+            }
+        }
+
+        $this->renderableSharedCacheIsSet = true;
+
+        return $this->renderableSharedCache;
+    }
 }
diff --git a/src/Illuminate/View/View.php b/src/Illuminate/View/View.php
index 0751a8dff5ba..8cd0037b3fa3 100755
--- a/src/Illuminate/View/View.php
+++ b/src/Illuminate/View/View.php
@@ -215,7 +215,7 @@ protected function getContents()
      */
     public function gatherData()
     {
-        $data = array_merge($this->factory->getShared(), $this->data);
+        $data = $this->data;
 
         foreach ($data as $key => $value) {
             if ($value instanceof Renderable) {
@@ -223,7 +223,7 @@ public function gatherData()
             }
         }
 
-        return $data;
+        return array_merge($this->factory->getRenderableShared(), $data);
     }
 
     /**
@@ -305,7 +305,7 @@ protected function formatErrors($provider)
      */
     public function name()
     {
-        return $this->getName();
+        return $this->view;
     }
 
     /**

From 3846840c6d10094bf15fc0121609715e9d5870e5 Mon Sep 17 00:00:00 2001
From: Lonny Kapelushnik <lonny@lonnylot.com>
Date: Sun, 28 Apr 2024 20:11:01 -0600
Subject: [PATCH 2/2] Corrected fields; updated tests

---
 src/Illuminate/View/AnonymousComponent.php         |  2 +-
 tests/View/Blade/BladeComponentTagCompilerTest.php | 14 +++++++-------
 2 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/src/Illuminate/View/AnonymousComponent.php b/src/Illuminate/View/AnonymousComponent.php
index 3cb1c1783974..f9601e04250d 100644
--- a/src/Illuminate/View/AnonymousComponent.php
+++ b/src/Illuminate/View/AnonymousComponent.php
@@ -50,7 +50,7 @@ public function render()
      */
     public static function resolve($data)
     {
-        return new static(...$data);
+        return new static($data['view'], $data['data'], $data['factory']);
     }
 
     /**
diff --git a/tests/View/Blade/BladeComponentTagCompilerTest.php b/tests/View/Blade/BladeComponentTagCompilerTest.php
index 38a4a037b21a..2fa1f4d28a59 100644
--- a/tests/View/Blade/BladeComponentTagCompilerTest.php
+++ b/tests/View/Blade/BladeComponentTagCompilerTest.php
@@ -474,7 +474,7 @@ public function testClasslessComponents()
 
         $result = $this->compiler()->compileTags('<x-anonymous-component :name="\'Taylor\'" :age="31" wire:model="foo" />');
 
-        $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\View\AnonymousComponent', 'anonymous-component', ['view' => 'components.anonymous-component','data' => ['name' => 'Taylor','age' => 31,'wire:model' => 'foo']])
+        $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\View\AnonymousComponent', 'anonymous-component', ['view' => 'components.anonymous-component','data' => ['name' => 'Taylor','age' => 31,'wire:model' => 'foo'],'factory' => \$__env])
 <?php if (isset(\$attributes) && \$attributes instanceof Illuminate\View\ComponentAttributeBag): ?>
 <?php \$attributes = \$attributes->except(\Illuminate\View\AnonymousComponent::ignoredParameterNames()); ?>
 <?php endif; ?>
@@ -493,7 +493,7 @@ public function testClasslessComponentsWithIndexView()
 
         $result = $this->compiler()->compileTags('<x-anonymous-component :name="\'Taylor\'" :age="31" wire:model="foo" />');
 
-        $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\View\AnonymousComponent', 'anonymous-component', ['view' => 'components.anonymous-component.index','data' => ['name' => 'Taylor','age' => 31,'wire:model' => 'foo']])
+        $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\View\AnonymousComponent', 'anonymous-component', ['view' => 'components.anonymous-component.index','data' => ['name' => 'Taylor','age' => 31,'wire:model' => 'foo'],'factory' => \$__env])
 <?php if (isset(\$attributes) && \$attributes instanceof Illuminate\View\ComponentAttributeBag): ?>
 <?php \$attributes = \$attributes->except(\Illuminate\View\AnonymousComponent::ignoredParameterNames()); ?>
 <?php endif; ?>
@@ -512,7 +512,7 @@ public function testPackagesClasslessComponents()
 
         $result = $this->compiler()->compileTags('<x-package::anonymous-component :name="\'Taylor\'" :age="31" wire:model="foo" />');
 
-        $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\View\AnonymousComponent', 'package::anonymous-component', ['view' => 'package::components.anonymous-component','data' => ['name' => 'Taylor','age' => 31,'wire:model' => 'foo']])
+        $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\View\AnonymousComponent', 'package::anonymous-component', ['view' => 'package::components.anonymous-component','data' => ['name' => 'Taylor','age' => 31,'wire:model' => 'foo'],'factory' => \$__env])
 <?php if (isset(\$attributes) && \$attributes instanceof Illuminate\View\ComponentAttributeBag): ?>
 <?php \$attributes = \$attributes->except(\Illuminate\View\AnonymousComponent::ignoredParameterNames()); ?>
 <?php endif; ?>
@@ -546,7 +546,7 @@ public function testClasslessComponentsWithAnonymousComponentNamespace()
 
         $result = $compiler->compileTags('<x-frontend::anonymous-component :name="\'Taylor\'" :age="31" wire:model="foo" />');
 
-        $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\View\AnonymousComponent', 'frontend::anonymous-component', ['view' => 'public.frontend.anonymous-component','data' => ['name' => 'Taylor','age' => 31,'wire:model' => 'foo']])
+        $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\View\AnonymousComponent', 'frontend::anonymous-component', ['view' => 'public.frontend.anonymous-component','data' => ['name' => 'Taylor','age' => 31,'wire:model' => 'foo'],'factory' => \$__env])
 <?php if (isset(\$attributes) && \$attributes instanceof Illuminate\View\ComponentAttributeBag): ?>
 <?php \$attributes = \$attributes->except(\Illuminate\View\AnonymousComponent::ignoredParameterNames()); ?>
 <?php endif; ?>
@@ -580,7 +580,7 @@ public function testClasslessComponentsWithAnonymousComponentNamespaceWithIndexV
 
         $result = $compiler->compileTags('<x-admin.auth::anonymous-component :name="\'Taylor\'" :age="31" wire:model="foo" />');
 
-        $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\View\AnonymousComponent', 'admin.auth::anonymous-component', ['view' => 'admin.auth.components.anonymous-component.index','data' => ['name' => 'Taylor','age' => 31,'wire:model' => 'foo']])
+        $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\View\AnonymousComponent', 'admin.auth::anonymous-component', ['view' => 'admin.auth.components.anonymous-component.index','data' => ['name' => 'Taylor','age' => 31,'wire:model' => 'foo'],'factory' => \$__env])
 <?php if (isset(\$attributes) && \$attributes instanceof Illuminate\View\ComponentAttributeBag): ?>
 <?php \$attributes = \$attributes->except(\Illuminate\View\AnonymousComponent::ignoredParameterNames()); ?>
 <?php endif; ?>
@@ -613,7 +613,7 @@ public function testClasslessComponentsWithAnonymousComponentPath()
 
         $result = $compiler->compileTags('<x-panel />');
 
-        $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\View\AnonymousComponent', 'panel', ['view' => '".md5('test-directory')."::panel.index','data' => []])
+        $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\View\AnonymousComponent', 'panel', ['view' => '".md5('test-directory')."::panel.index','data' => [],'factory' => \$__env])
 <?php if (isset(\$attributes) && \$attributes instanceof Illuminate\View\ComponentAttributeBag): ?>
 <?php \$attributes = \$attributes->except(\Illuminate\View\AnonymousComponent::ignoredParameterNames()); ?>
 <?php endif; ?>
@@ -646,7 +646,7 @@ public function testClasslessIndexComponentsWithAnonymousComponentPath()
 
         $result = $compiler->compileTags('<x-panel />');
 
-        $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\View\AnonymousComponent', 'panel', ['view' => '".md5('test-directory')."::panel','data' => []])
+        $this->assertSame("##BEGIN-COMPONENT-CLASS##@component('Illuminate\View\AnonymousComponent', 'panel', ['view' => '".md5('test-directory')."::panel','data' => [],'factory' => \$__env])
 <?php if (isset(\$attributes) && \$attributes instanceof Illuminate\View\ComponentAttributeBag): ?>
 <?php \$attributes = \$attributes->except(\Illuminate\View\AnonymousComponent::ignoredParameterNames()); ?>
 <?php endif; ?>