[ Index ] |
PHP Cross Reference of Joomla 4.2.2 documentation |
[Summary view] [Print] [Text view]
1 <?php 2 3 /** 4 * Joomla! Content Management System 5 * 6 * @copyright (C) 2005 Open Source Matters, Inc. <https://www.joomla.org> 7 * @license GNU General Public License version 2 or later; see LICENSE.txt 8 9 * @phpcs:disable PSR1.Classes.ClassDeclaration.MissingNamespace 10 */ 11 12 defined('JPATH_PLATFORM') or die; 13 14 /** 15 * Static class to handle loading of libraries. 16 * 17 * @since 1.7.0 18 */ 19 abstract class JLoader 20 { 21 /** 22 * Container for already imported library paths. 23 * 24 * @var array 25 * @since 1.7.0 26 */ 27 protected static $classes = array(); 28 29 /** 30 * Container for already imported library paths. 31 * 32 * @var array 33 * @since 1.7.0 34 */ 35 protected static $imported = array(); 36 37 /** 38 * Container for registered library class prefixes and path lookups. 39 * 40 * @var array 41 * @since 3.0.0 42 */ 43 protected static $prefixes = array(); 44 45 /** 46 * Holds proxy classes and the class names the proxy. 47 * 48 * @var array 49 * @since 3.2 50 */ 51 protected static $classAliases = array(); 52 53 /** 54 * Holds the inverse lookup for proxy classes and the class names the proxy. 55 * 56 * @var array 57 * @since 3.4 58 */ 59 protected static $classAliasesInverse = array(); 60 61 /** 62 * Container for namespace => path map. 63 * 64 * @var array 65 * @since 3.1.4 66 */ 67 protected static $namespaces = array(); 68 69 /** 70 * Holds a reference for all deprecated aliases (mainly for use by a logging platform). 71 * 72 * @var array 73 * @since 3.6.3 74 */ 75 protected static $deprecatedAliases = array(); 76 77 /** 78 * The root folders where extensions can be found. 79 * 80 * @var array 81 * @since 4.0.0 82 */ 83 protected static $extensionRootFolders = array(); 84 85 /** 86 * Method to discover classes of a given type in a given path. 87 * 88 * @param string $classPrefix The class name prefix to use for discovery. 89 * @param string $parentPath Full path to the parent folder for the classes to discover. 90 * @param boolean $force True to overwrite the autoload path value for the class if it already exists. 91 * @param boolean $recurse Recurse through all child directories as well as the parent path. 92 * 93 * @return void 94 * 95 * @since 1.7.0 96 * @deprecated 5.0 Classes should be autoloaded. Use JLoader::registerPrefix() or JLoader::registerNamespace() to register an autoloader for 97 * your files. 98 */ 99 public static function discover($classPrefix, $parentPath, $force = true, $recurse = false) 100 { 101 try { 102 if ($recurse) { 103 $iterator = new RecursiveIteratorIterator( 104 new RecursiveDirectoryIterator($parentPath), 105 RecursiveIteratorIterator::SELF_FIRST 106 ); 107 } else { 108 $iterator = new DirectoryIterator($parentPath); 109 } 110 111 /** @type $file DirectoryIterator */ 112 foreach ($iterator as $file) { 113 $fileName = $file->getFilename(); 114 115 // Only load for php files. 116 if ($file->isFile() && $file->getExtension() === 'php') { 117 // Get the class name and full path for each file. 118 $class = strtolower($classPrefix . preg_replace('#\.php$#', '', $fileName)); 119 120 // Register the class with the autoloader if not already registered or the force flag is set. 121 if ($force || empty(self::$classes[$class])) { 122 self::register($class, $file->getPath() . '/' . $fileName); 123 } 124 } 125 } 126 } catch (UnexpectedValueException $e) { 127 // Exception will be thrown if the path is not a directory. Ignore it. 128 } 129 } 130 131 /** 132 * Method to get the list of registered classes and their respective file paths for the autoloader. 133 * 134 * @return array The array of class => path values for the autoloader. 135 * 136 * @since 1.7.0 137 */ 138 public static function getClassList() 139 { 140 return self::$classes; 141 } 142 143 /** 144 * Method to get the list of deprecated class aliases. 145 * 146 * @return array An associative array with deprecated class alias data. 147 * 148 * @since 3.6.3 149 */ 150 public static function getDeprecatedAliases() 151 { 152 return self::$deprecatedAliases; 153 } 154 155 /** 156 * Method to get the list of registered namespaces. 157 * 158 * @return array The array of namespace => path values for the autoloader. 159 * 160 * @since 3.1.4 161 */ 162 public static function getNamespaces() 163 { 164 return self::$namespaces; 165 } 166 167 /** 168 * Loads a class from specified directories. 169 * 170 * @param string $key The class name to look for (dot notation). 171 * @param string $base Search this directory for the class. 172 * 173 * @return boolean True on success. 174 * 175 * @since 1.7.0 176 * @deprecated 5.0 Classes should be autoloaded. Use JLoader::registerPrefix() or JLoader::registerNamespace() to register an autoloader for 177 * your files. 178 */ 179 public static function import($key, $base = null) 180 { 181 // Only import the library if not already attempted. 182 if (!isset(self::$imported[$key])) { 183 // Setup some variables. 184 $success = false; 185 $parts = explode('.', $key); 186 $class = array_pop($parts); 187 $base = (!empty($base)) ? $base : __DIR__; 188 $path = str_replace('.', DIRECTORY_SEPARATOR, $key); 189 190 // Handle special case for helper classes. 191 if ($class === 'helper') { 192 $class = ucfirst(array_pop($parts)) . ucfirst($class); 193 } else { 194 // Standard class. 195 $class = ucfirst($class); 196 } 197 198 // If we are importing a library from the Joomla namespace set the class to autoload. 199 if (strpos($path, 'joomla') === 0) { 200 // Since we are in the Joomla namespace prepend the classname with J. 201 $class = 'J' . $class; 202 203 // Only register the class for autoloading if the file exists. 204 if (is_file($base . '/' . $path . '.php')) { 205 self::$classes[strtolower($class)] = $base . '/' . $path . '.php'; 206 $success = true; 207 } 208 } else { 209 /** 210 * If we are not importing a library from the Joomla namespace directly include the 211 * file since we cannot assert the file/folder naming conventions. 212 */ 213 // If the file exists attempt to include it. 214 if (is_file($base . '/' . $path . '.php')) { 215 $success = (bool) include_once $base . '/' . $path . '.php'; 216 } 217 } 218 219 // Add the import key to the memory cache container. 220 self::$imported[$key] = $success; 221 } 222 223 return self::$imported[$key]; 224 } 225 226 /** 227 * Load the file for a class. 228 * 229 * @param string $class The class to be loaded. 230 * 231 * @return boolean True on success 232 * 233 * @since 1.7.0 234 */ 235 public static function load($class) 236 { 237 // Sanitize class name. 238 $key = strtolower($class); 239 240 // If the class already exists do nothing. 241 if (class_exists($class, false)) { 242 return true; 243 } 244 245 // If the class is registered include the file. 246 if (isset(self::$classes[$key])) { 247 $found = (bool) include_once self::$classes[$key]; 248 249 if ($found) { 250 self::loadAliasFor($class); 251 } 252 253 // If the class doesn't exists, we probably have a class alias available 254 if (!class_exists($class, false)) { 255 // Search the alias class, first none namespaced and then namespaced 256 $original = array_search($class, self::$classAliases) ? : array_search('\\' . $class, self::$classAliases); 257 258 // When we have an original and the class exists an alias should be created 259 if ($original && class_exists($original, false)) { 260 class_alias($original, $class); 261 } 262 } 263 264 return true; 265 } 266 267 return false; 268 } 269 270 /** 271 * Directly register a class to the autoload list. 272 * 273 * @param string $class The class name to register. 274 * @param string $path Full path to the file that holds the class to register. 275 * @param boolean $force True to overwrite the autoload path value for the class if it already exists. 276 * 277 * @return void 278 * 279 * @since 1.7.0 280 * @deprecated 5.0 Classes should be autoloaded. Use JLoader::registerPrefix() or JLoader::registerNamespace() to register an autoloader for 281 * your files. 282 */ 283 public static function register($class, $path, $force = true) 284 { 285 // When an alias exists, register it as well 286 if (array_key_exists(strtolower($class), self::$classAliases)) { 287 self::register(self::stripFirstBackslash(self::$classAliases[strtolower($class)]), $path, $force); 288 } 289 290 // Sanitize class name. 291 $class = strtolower($class); 292 293 // Only attempt to register the class if the name and file exist. 294 if (!empty($class) && is_file($path)) { 295 // Register the class with the autoloader if not already registered or the force flag is set. 296 if ($force || empty(self::$classes[$class])) { 297 self::$classes[$class] = $path; 298 } 299 } 300 } 301 302 /** 303 * Register a class prefix with lookup path. This will allow developers to register library 304 * packages with different class prefixes to the system autoloader. More than one lookup path 305 * may be registered for the same class prefix, but if this method is called with the reset flag 306 * set to true then any registered lookups for the given prefix will be overwritten with the current 307 * lookup path. When loaded, prefix paths are searched in a "last in, first out" order. 308 * 309 * @param string $prefix The class prefix to register. 310 * @param string $path Absolute file path to the library root where classes with the given prefix can be found. 311 * @param boolean $reset True to reset the prefix with only the given lookup path. 312 * @param boolean $prepend If true, push the path to the beginning of the prefix lookup paths array. 313 * 314 * @return void 315 * 316 * @throws RuntimeException 317 * 318 * @since 3.0.0 319 */ 320 public static function registerPrefix($prefix, $path, $reset = false, $prepend = false) 321 { 322 // Verify the library path exists. 323 if (!is_dir($path)) { 324 $path = (str_replace(JPATH_ROOT, '', $path) == $path) ? basename($path) : str_replace(JPATH_ROOT, '', $path); 325 326 throw new RuntimeException('Library path ' . $path . ' cannot be found.', 500); 327 } 328 329 // If the prefix is not yet registered or we have an explicit reset flag then set set the path. 330 if ($reset || !isset(self::$prefixes[$prefix])) { 331 self::$prefixes[$prefix] = array($path); 332 } else { 333 // Otherwise we want to simply add the path to the prefix. 334 if ($prepend) { 335 array_unshift(self::$prefixes[$prefix], $path); 336 } else { 337 self::$prefixes[$prefix][] = $path; 338 } 339 } 340 } 341 342 /** 343 * Offers the ability for "just in time" usage of `class_alias()`. 344 * You cannot overwrite an existing alias. 345 * 346 * @param string $alias The alias name to register. 347 * @param string $original The original class to alias. 348 * @param string|boolean $version The version in which the alias will no longer be present. 349 * 350 * @return boolean True if registration was successful. False if the alias already exists. 351 * 352 * @since 3.2 353 */ 354 public static function registerAlias($alias, $original, $version = false) 355 { 356 // PHP is case insensitive so support all kind of alias combination 357 $lowercasedAlias = strtolower($alias); 358 359 if (!isset(self::$classAliases[$lowercasedAlias])) { 360 self::$classAliases[$lowercasedAlias] = $original; 361 362 $original = self::stripFirstBackslash($original); 363 364 if (!isset(self::$classAliasesInverse[$original])) { 365 self::$classAliasesInverse[$original] = array($lowercasedAlias); 366 } else { 367 self::$classAliasesInverse[$original][] = $lowercasedAlias; 368 } 369 370 // If given a version, log this alias as deprecated 371 if ($version) { 372 self::$deprecatedAliases[] = array('old' => $alias, 'new' => $original, 'version' => $version); 373 } 374 375 return true; 376 } 377 378 return false; 379 } 380 381 /** 382 * Register a namespace to the autoloader. When loaded, namespace paths are searched in a "last in, first out" order. 383 * 384 * @param string $namespace A case sensitive Namespace to register. 385 * @param string $path A case sensitive absolute file path to the library root where classes of the given namespace can be found. 386 * @param boolean $reset True to reset the namespace with only the given lookup path. 387 * @param boolean $prepend If true, push the path to the beginning of the namespace lookup paths array. 388 * 389 * @return void 390 * 391 * @throws RuntimeException 392 * 393 * @since 3.1.4 394 */ 395 public static function registerNamespace($namespace, $path, $reset = false, $prepend = false) 396 { 397 // Verify the library path exists. 398 if (!is_dir($path)) { 399 $path = (str_replace(JPATH_ROOT, '', $path) == $path) ? basename($path) : str_replace(JPATH_ROOT, '', $path); 400 401 throw new RuntimeException('Library path ' . $path . ' cannot be found.', 500); 402 } 403 404 // Trim leading and trailing backslashes from namespace, allowing "\Parent\Child", "Parent\Child\" and "\Parent\Child\" to be treated the same way. 405 $namespace = trim($namespace, '\\'); 406 407 // If the namespace is not yet registered or we have an explicit reset flag then set the path. 408 if ($reset || !isset(self::$namespaces[$namespace])) { 409 self::$namespaces[$namespace] = array($path); 410 } else { 411 // Otherwise we want to simply add the path to the namespace. 412 if ($prepend) { 413 array_unshift(self::$namespaces[$namespace], $path); 414 } else { 415 self::$namespaces[$namespace][] = $path; 416 } 417 } 418 } 419 420 /** 421 * Method to setup the autoloaders for the Joomla Platform. 422 * Since the SPL autoloaders are called in a queue we will add our explicit 423 * class-registration based loader first, then fall back on the autoloader based on conventions. 424 * This will allow people to register a class in a specific location and override platform libraries 425 * as was previously possible. 426 * 427 * @param boolean $enablePsr True to enable autoloading based on PSR-0. 428 * @param boolean $enablePrefixes True to enable prefix based class loading (needed to auto load the Joomla core). 429 * @param boolean $enableClasses True to enable class map based class loading (needed to auto load the Joomla core). 430 * 431 * @return void 432 * 433 * @since 3.1.4 434 */ 435 public static function setup($enablePsr = true, $enablePrefixes = true, $enableClasses = true) 436 { 437 if ($enableClasses) { 438 // Register the class map based autoloader. 439 spl_autoload_register(array('JLoader', 'load')); 440 } 441 442 if ($enablePrefixes) { 443 // Register the prefix autoloader. 444 spl_autoload_register(array('JLoader', '_autoload')); 445 } 446 447 if ($enablePsr) { 448 // Register the PSR based autoloader. 449 spl_autoload_register(array('JLoader', 'loadByPsr')); 450 spl_autoload_register(array('JLoader', 'loadByAlias')); 451 } 452 } 453 454 /** 455 * Method to autoload classes that are namespaced to the PSR-4 standard. 456 * 457 * @param string $class The fully qualified class name to autoload. 458 * 459 * @return boolean True on success, false otherwise. 460 * 461 * @since 3.7.0 462 * @deprecated 5.0 Use JLoader::loadByPsr instead 463 */ 464 public static function loadByPsr4($class) 465 { 466 return self::loadByPsr($class); 467 } 468 469 /** 470 * Method to autoload classes that are namespaced to the PSR-4 standard. 471 * 472 * @param string $class The fully qualified class name to autoload. 473 * 474 * @return boolean True on success, false otherwise. 475 * 476 * @since 4.0.0 477 */ 478 public static function loadByPsr($class) 479 { 480 $class = self::stripFirstBackslash($class); 481 482 // Find the location of the last NS separator. 483 $pos = strrpos($class, '\\'); 484 485 // If one is found, we're dealing with a NS'd class. 486 if ($pos !== false) { 487 $classPath = str_replace('\\', DIRECTORY_SEPARATOR, substr($class, 0, $pos)) . DIRECTORY_SEPARATOR; 488 $className = substr($class, $pos + 1); 489 } else { 490 // If not, no need to parse path. 491 $classPath = null; 492 $className = $class; 493 } 494 495 $classPath .= $className . '.php'; 496 497 // Loop through registered namespaces until we find a match. 498 foreach (self::$namespaces as $ns => $paths) { 499 if (strpos($class, "{$ns}\\") === 0) { 500 $nsPath = trim(str_replace('\\', DIRECTORY_SEPARATOR, $ns), DIRECTORY_SEPARATOR); 501 502 // Loop through paths registered to this namespace until we find a match. 503 foreach ($paths as $path) { 504 $classFilePath = realpath($path . DIRECTORY_SEPARATOR . substr_replace($classPath, '', 0, strlen($nsPath) + 1)); 505 506 // We do not allow files outside the namespace root to be loaded 507 if (strpos($classFilePath, realpath($path)) !== 0) { 508 continue; 509 } 510 511 // We check for class_exists to handle case-sensitive file systems 512 if (is_file($classFilePath) && !class_exists($class, false)) { 513 $found = (bool) include_once $classFilePath; 514 515 if ($found) { 516 self::loadAliasFor($class); 517 } 518 519 return $found; 520 } 521 } 522 } 523 } 524 525 return false; 526 } 527 528 /** 529 * Method to autoload classes that have been aliased using the registerAlias method. 530 * 531 * @param string $class The fully qualified class name to autoload. 532 * 533 * @return boolean True on success, false otherwise. 534 * 535 * @since 3.2 536 */ 537 public static function loadByAlias($class) 538 { 539 $class = strtolower(self::stripFirstBackslash($class)); 540 541 if (isset(self::$classAliases[$class])) { 542 // Force auto-load of the regular class 543 class_exists(self::$classAliases[$class], true); 544 545 // Normally this shouldn't execute as the autoloader will execute applyAliasFor when the regular class is 546 // auto-loaded above. 547 if (!class_exists($class, false) && !interface_exists($class, false)) { 548 class_alias(self::$classAliases[$class], $class); 549 } 550 } 551 } 552 553 /** 554 * Applies a class alias for an already loaded class, if a class alias was created for it. 555 * 556 * @param string $class We'll look for and register aliases for this (real) class name 557 * 558 * @return void 559 * 560 * @since 3.4 561 */ 562 public static function applyAliasFor($class) 563 { 564 $class = self::stripFirstBackslash($class); 565 566 if (isset(self::$classAliasesInverse[$class])) { 567 foreach (self::$classAliasesInverse[$class] as $alias) { 568 class_alias($class, $alias); 569 } 570 } 571 } 572 573 /** 574 * Autoload a class based on name. 575 * 576 * @param string $class The class to be loaded. 577 * 578 * @return boolean True if the class was loaded, false otherwise. 579 * 580 * @since 1.7.3 581 */ 582 public static function _autoload($class) 583 { 584 foreach (self::$prefixes as $prefix => $lookup) { 585 $chr = strlen($prefix) < strlen($class) ? $class[strlen($prefix)] : 0; 586 587 if (strpos($class, $prefix) === 0 && ($chr === strtoupper($chr))) { 588 return self::_load(substr($class, strlen($prefix)), $lookup); 589 } 590 } 591 592 return false; 593 } 594 595 /** 596 * Load a class based on name and lookup array. 597 * 598 * @param string $class The class to be loaded (without prefix). 599 * @param array $lookup The array of base paths to use for finding the class file. 600 * 601 * @return boolean True if the class was loaded, false otherwise. 602 * 603 * @since 3.0.0 604 */ 605 private static function _load($class, $lookup) 606 { 607 // Split the class name into parts separated by camelCase. 608 $parts = preg_split('/(?<=[a-z0-9])(?=[A-Z])/x', $class); 609 $partsCount = count($parts); 610 611 foreach ($lookup as $base) { 612 // Generate the path based on the class name parts. 613 $path = realpath($base . '/' . implode('/', array_map('strtolower', $parts)) . '.php'); 614 615 // Load the file if it exists and is in the lookup path. 616 if (strpos($path, realpath($base)) === 0 && is_file($path)) { 617 $found = (bool) include_once $path; 618 619 if ($found) { 620 self::loadAliasFor($class); 621 } 622 623 return $found; 624 } 625 626 // Backwards compatibility patch 627 628 // If there is only one part we want to duplicate that part for generating the path. 629 if ($partsCount === 1) { 630 // Generate the path based on the class name parts. 631 $path = realpath($base . '/' . implode('/', array_map('strtolower', array($parts[0], $parts[0]))) . '.php'); 632 633 // Load the file if it exists and is in the lookup path. 634 if (strpos($path, realpath($base)) === 0 && is_file($path)) { 635 $found = (bool) include_once $path; 636 637 if ($found) { 638 self::loadAliasFor($class); 639 } 640 641 return $found; 642 } 643 } 644 } 645 646 return false; 647 } 648 649 /** 650 * Loads the aliases for the given class. 651 * 652 * @param string $class The class. 653 * 654 * @return void 655 * 656 * @since 3.8.0 657 */ 658 private static function loadAliasFor($class) 659 { 660 if (!array_key_exists($class, self::$classAliasesInverse)) { 661 return; 662 } 663 664 foreach (self::$classAliasesInverse[$class] as $alias) { 665 // Force auto-load of the alias class 666 class_exists($alias, true); 667 } 668 } 669 670 /** 671 * Strips the first backslash from the given class if present. 672 * 673 * @param string $class The class to strip the first prefix from. 674 * 675 * @return string The striped class name. 676 * 677 * @since 3.8.0 678 */ 679 private static function stripFirstBackslash($class) 680 { 681 return $class && $class[0] === '\\' ? substr($class, 1) : $class; 682 } 683 } 684 685 // Check if jexit is defined first (our unit tests mock this) 686 if (!function_exists('jexit')) { 687 /** 688 * Global application exit. 689 * 690 * This function provides a single exit point for the platform. 691 * 692 * @param mixed $message Exit code or string. Defaults to zero. 693 * 694 * @return void 695 * 696 * @codeCoverageIgnore 697 * @since 1.7.0 698 */ 699 function jexit($message = 0) 700 { 701 exit($message); 702 } 703 } 704 705 /** 706 * Intelligent file importer. 707 * 708 * @param string $path A dot syntax path. 709 * @param string $base Search this directory for the class. 710 * 711 * @return boolean True on success. 712 * 713 * @since 1.7.0 714 * @deprecated 5.0 Classes should be autoloaded. Use JLoader::registerPrefix() or JLoader::registerNamespace() to register an autoloader for 715 * your files. 716 */ 717 function jimport($path, $base = null) 718 { 719 return JLoader::import($path, $base); 720 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Wed Sep 7 05:41:13 2022 | Chilli.vc Blog - For Webmaster,Blog-Writer,System Admin and Domainer |