-
Notifications
You must be signed in to change notification settings - Fork 7.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Driver extension enhancement #1787
Changes from all commits
28bee3d
b9981f6
1db3e0e
0fc5320
dd887a2
9576deb
9caf878
f0e2924
52bcffb
5af440d
b1ddeb0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,7 +9,7 @@ | |
* Licensed under the Open Software License version 3.0 | ||
* | ||
* This source file is subject to the Open Software License (OSL 3.0) that is | ||
* bundled with this package in the files license.txt / license.rst. It is | ||
* bundled with this package in the files license.txt / license.rst. It is | ||
* also available through the world wide web at this URL: | ||
* http://opensource.org/licenses/OSL-3.0 | ||
* If you did not receive a copy of the license and are unable to obtain it | ||
|
@@ -136,7 +136,7 @@ class CI_Loader { | |
*/ | ||
public function __construct() | ||
{ | ||
$this->_ci_ob_level = ob_get_level(); | ||
$this->_ci_ob_level = ob_get_level(); | ||
$this->_ci_library_paths = array(APPPATH, BASEPATH); | ||
$this->_ci_helper_paths = array(APPPATH, BASEPATH); | ||
$this->_ci_model_paths = array(APPPATH); | ||
|
@@ -949,109 +949,137 @@ protected function _ci_load_class($class, $params = NULL, $object_name = NULL) | |
|
||
// Get the filename from the path | ||
$class = substr($class, $last_slash); | ||
} | ||
|
||
// Check for match and driver base class | ||
if (strtolower(trim($subdir, '/')) == strtolower($class) && ! class_exists('CI_Driver_Library')) | ||
// Establish subdirectories to try - if one was specified, just use that | ||
$trysubs = array($subdir); | ||
if ($subdir === '') | ||
{ | ||
// Also check subdirectories matching class name | ||
// This allows us to find libraries in self-named subdirectories | ||
// (like Drivers) and extensions for those in the main libraries dir | ||
$dir = strtolower($class).'/'; | ||
$trysubs[] = ucfirst($dir); | ||
|
||
// If we aren't case-insensitive, check lowercase too | ||
if (DIRECTORY_SEPARATOR !== '\\') | ||
{ | ||
// We aren't instantiating an object here, just making the base class available | ||
require BASEPATH.'libraries/Driver.php'; | ||
$trysubs[] = $dir; | ||
} | ||
} | ||
|
||
// Get the subclass prefix | ||
$prefix = config_item('subclass_prefix'); | ||
|
||
// We'll test for both lowercase and capitalized versions of the file name | ||
foreach (array(ucfirst($class), strtolower($class)) as $class) | ||
$cases = array(ucfirst($class)); | ||
if (DIRECTORY_SEPARATOR !== '\\') | ||
{ | ||
// Case-sensitive - try lowercase too | ||
$cases[] = strtolower($class); | ||
} | ||
foreach ($cases as $class) | ||
{ | ||
$subclass = APPPATH.'libraries/'.$subdir.config_item('subclass_prefix').$class.'.php'; | ||
|
||
// Is this a class extension request? | ||
if (file_exists($subclass)) | ||
foreach($trysubs as $dir) | ||
{ | ||
$baseclass = BASEPATH.'libraries/'.ucfirst($class).'.php'; | ||
|
||
if ( ! file_exists($baseclass)) | ||
// Check each path for an extension file | ||
$subclass = APPPATH.'libraries/'.$dir.$prefix.$class.'.php'; | ||
if (file_exists($subclass)) | ||
{ | ||
log_message('error', 'Unable to load the requested class: '.$class); | ||
show_error('Unable to load the requested class: '.$class); | ||
} | ||
// Require the base class in the same directory | ||
$baseclass = BASEPATH.'libraries/'.$dir.ucfirst($class).'.php'; | ||
if ( ! file_exists($baseclass)) | ||
{ | ||
// No base matches extension - bail | ||
$msg = 'Unable to load the requested class: '.$class; | ||
log_message('error', $msg); | ||
show_error($msg); | ||
} | ||
|
||
// Safety: Was the class already loaded by a previous call? | ||
if (in_array($subclass, $this->_ci_loaded_files)) | ||
{ | ||
// Before we deem this to be a duplicate request, let's see | ||
// if a custom object name is being supplied. If so, we'll | ||
// return a new instance of the object | ||
if ( ! is_null($object_name)) | ||
// Does this look like a driver? | ||
if (strtolower($dir) === strtolower($class).'/' && ! class_exists('CI_Driver_Library')) | ||
{ | ||
// We aren't instantiating an object here, just making the base class available | ||
require BASEPATH.'libraries/Driver.php'; | ||
} | ||
|
||
// Safety: Was the class already loaded by a previous call? | ||
if (in_array($subclass, $this->_ci_loaded_files)) | ||
{ | ||
$CI =& get_instance(); | ||
if ( ! isset($CI->$object_name)) | ||
// Before we deem this to be a duplicate request, let's see | ||
// if a custom object name is being supplied. If so, we'll | ||
// return a new instance of the object | ||
if ( ! is_null($object_name)) | ||
{ | ||
return $this->_ci_init_class($class, config_item('subclass_prefix'), $params, $object_name); | ||
$CI =& get_instance(); | ||
if ( ! isset($CI->$object_name)) | ||
{ | ||
return $this->_ci_init_class($class, $prefix, $params, $object_name); | ||
} | ||
} | ||
} | ||
|
||
$is_duplicate = TRUE; | ||
log_message('debug', $class.' class already loaded. Second attempt ignored.'); | ||
return; | ||
} | ||
$is_duplicate = TRUE; | ||
log_message('debug', $class.' class already loaded. Second attempt ignored.'); | ||
return; | ||
} | ||
|
||
include_once($baseclass); | ||
include_once($subclass); | ||
$this->_ci_loaded_files[] = $subclass; | ||
include($baseclass); | ||
include($subclass); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK, I'll change this if you say so, but I don't see the point in require_once for these files. The Loader already tracks what's been loaded, and we've already verified both files exist. Am I missing some reason for having PHP do the extra work of require_once over include in this scenario? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Simple - it is way better to leave to job to PHP instead of trying to track it yourself. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's just it, though - Loader has always tracked loaded classes internally in order to recognize duplicate requests and either skip the include to instantiate another object under a different name, or gracefully return on true duplicates after providing a log message to inform the developer of the redundant call. If we remove that legacy logic and just rely on require_once, we will lose that courtesy. So, which way do we want to go - internal tracking or require_once? I don't see any point in doing both - it's just wasteful. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Save library names in a property, leave PHP to handle file includes. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. OK, last push on this - if you insist, I'll make those require_once() even though I disagree. The difference between include() and require_once() is making sure the file exists and hasn't already been included. If the library name isn't already in the property, we know the file hasn't been included yet. If we found the file in the current directory, we already know it exists. These are steps we have to take in our loading process. So, why have PHP repeat those same checks? It's redundant and inefficient. As I said above, if you insist on that redundancy, I'll make the change and shut up about it. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My whole point is - I don't get the whole idea of why do we have to have a On a side note - I don't really care if it is |
||
$this->_ci_loaded_files[] = $subclass; | ||
|
||
return $this->_ci_init_class($class, config_item('subclass_prefix'), $params, $object_name); | ||
return $this->_ci_init_class($class, $prefix, $params, $object_name); | ||
} | ||
} | ||
|
||
// Lets search for the requested library file and load it. | ||
$is_duplicate = FALSE; | ||
foreach ($this->_ci_library_paths as $path) | ||
{ | ||
$filepath = $path.'libraries/'.$subdir.$class.'.php'; | ||
|
||
// Does the file exist? No? Bummer... | ||
if ( ! file_exists($filepath)) | ||
foreach ($trysubs as $dir) | ||
{ | ||
continue; | ||
} | ||
$filepath = $path.'libraries/'.$dir.$class.'.php'; | ||
|
||
// Safety: Was the class already loaded by a previous call? | ||
if (in_array($filepath, $this->_ci_loaded_files)) | ||
{ | ||
// Before we deem this to be a duplicate request, let's see | ||
// if a custom object name is being supplied. If so, we'll | ||
// return a new instance of the object | ||
if ( ! is_null($object_name)) | ||
// Does the file exist? No? Bummer... | ||
if ( ! file_exists($filepath)) | ||
{ | ||
continue; | ||
} | ||
|
||
// Does this look like a driver? | ||
if (strtolower($dir) === strtolower($class).'/' && ! class_exists('CI_Driver_Library')) | ||
{ | ||
// We aren't instantiating an object here, just making the base class available | ||
require BASEPATH.'libraries/Driver.php'; | ||
} | ||
|
||
// Safety: Was the class already loaded by a previous call? | ||
if (in_array($filepath, $this->_ci_loaded_files)) | ||
{ | ||
$CI =& get_instance(); | ||
if ( ! isset($CI->$object_name)) | ||
// Before we deem this to be a duplicate request, let's see | ||
// if a custom object name is being supplied. If so, we'll | ||
// return a new instance of the object | ||
if ( ! is_null($object_name)) | ||
{ | ||
return $this->_ci_init_class($class, '', $params, $object_name); | ||
$CI =& get_instance(); | ||
if ( ! isset($CI->$object_name)) | ||
{ | ||
return $this->_ci_init_class($class, '', $params, $object_name); | ||
} | ||
} | ||
|
||
$is_duplicate = TRUE; | ||
log_message('debug', $class.' class already loaded. Second attempt ignored.'); | ||
return; | ||
} | ||
|
||
$is_duplicate = TRUE; | ||
log_message('debug', $class.' class already loaded. Second attempt ignored.'); | ||
return; | ||
include($filepath); | ||
$this->_ci_loaded_files[] = $filepath; | ||
return $this->_ci_init_class($class, '', $params, $object_name); | ||
} | ||
|
||
include_once($filepath); | ||
$this->_ci_loaded_files[] = $filepath; | ||
return $this->_ci_init_class($class, '', $params, $object_name); | ||
} | ||
} // END FOREACH | ||
|
||
// One last attempt. Maybe the library is in a subdirectory, but it wasn't specified? | ||
if ($subdir === '') | ||
{ | ||
$path = strtolower($class).'/'.$class; | ||
return $this->_ci_load_class($path, $params, $object_name); | ||
} | ||
elseif (ucfirst($subdir) != $subdir) | ||
{ | ||
// Lowercase subdir failed - retry capitalized | ||
$path = ucfirst($subdir).$class; | ||
return $this->_ci_load_class($path, $params, $object_name); | ||
} | ||
|
||
// If we got this far we were unable to find the requested class. | ||
// We do not issue errors if the load call failed due to a duplicate request | ||
if ($is_duplicate === FALSE) | ||
|
@@ -1324,4 +1352,4 @@ protected function _ci_prep_filename($filename, $extension) | |
} | ||
|
||
/* End of file Loader.php */ | ||
/* Location: ./system/core/Loader.php */ | ||
/* Location: ./system/core/Loader.php */ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Revert those, I think we already discussed them on another PR.