Return a class-loader closure from individual file-context components. Useful when the class list differs from what is stored in a `FileContext` (e.g. after re-parsing patched content for error recovery).
(
&'a self,
classes: &'a [Arc<ClassInfo>],
use_map: &'a HashMap<String, String>,
namespace: &'a Option<String>,
)
| 831 | /// `FileContext` (e.g. after re-parsing patched content for error |
| 832 | /// recovery). |
| 833 | pub(crate) fn class_loader_with<'a>( |
| 834 | &'a self, |
| 835 | classes: &'a [Arc<ClassInfo>], |
| 836 | use_map: &'a HashMap<String, String>, |
| 837 | namespace: &'a Option<String>, |
| 838 | ) -> impl Fn(&str) -> Option<Arc<ClassInfo>> + 'a { |
| 839 | move |name: &str| { |
| 840 | // For unqualified names (no `\`), check the use-map first. |
| 841 | // A `use Illuminate\Support\Facades\Event;` import must |
| 842 | // take priority over a global-namespace stub class named |
| 843 | // `Event` (e.g. the PECL event extension). Without this |
| 844 | // check, `find_or_load_class("Event")` would find the stub |
| 845 | // and short-circuit, never consulting the use-map. |
| 846 | let stripped = name.strip_prefix('\\').unwrap_or(name); |
| 847 | if !stripped.contains('\\') |
| 848 | && let Some(fqn) = use_map.get(stripped) |
| 849 | && let Some(cls) = self.find_or_load_class(fqn) |
| 850 | { |
| 851 | return Some(cls); |
| 852 | } |
| 853 | |
| 854 | // Try a direct FQN lookup. Names that arrive here are |
| 855 | // often already-resolved FQNs (e.g. `parent_class`, |
| 856 | // `used_traits`, `interfaces` — all canonicalised by |
| 857 | // `resolve_parent_class_names`). Passing a bare global |
| 858 | // name like `Exception` through namespace-aware resolution |
| 859 | // would incorrectly yield `Test\Exception` when a |
| 860 | // same-named class exists in the current namespace. |
| 861 | // |
| 862 | // The direct lookup is cheap (hash-map hit in fqn_index) |
| 863 | // and correct for FQNs. For user-typed unqualified names |
| 864 | // that should resolve via namespace context, the direct |
| 865 | // lookup will miss (no global class with that name) and |
| 866 | // we fall through to full resolution. |
| 867 | if let Some(cls) = self.find_or_load_class(stripped) { |
| 868 | return Some(cls); |
| 869 | } |
| 870 | // When the name is namespace-qualified (e.g. "App\IteratorAggregate") |
| 871 | // and the direct lookup failed, try the short name as a global class. |
| 872 | // This handles the case where resolve_parent_class_names prepended the |
| 873 | // file namespace to an unqualified global class name. |
| 874 | if stripped.contains('\\') { |
| 875 | let short = crate::util::short_name(stripped); |
| 876 | if let Some(cls) = self.find_or_load_class(short) { |
| 877 | return Some(cls); |
| 878 | } |
| 879 | } |
| 880 | self.resolve_class_name(name, classes, use_map, namespace) |
| 881 | } |
| 882 | } |
| 883 | |
| 884 | /// Return a function-loader closure bound to a [`FileContext`]. |
| 885 | /// |
no test coverage detected