Completed
Push — master ( 96358b...5204ad )
by Kenji
02:48
created

CI_Loader   D

Complexity

Total Complexity 168

Size/Duplication

Total Lines 1340
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Importance

Changes 0
Metric Value
dl 0
loc 1340
rs 4.4102
c 0
b 0
f 0
wmc 168
lcom 1
cbo 0

30 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 7 1
A initialize() 0 4 1
A is_loaded() 0 4 1
C library() 0 31 7
F model() 0 78 22
C database() 0 26 7
B dbutil() 0 22 5
C dbforge() 0 34 7
A view() 0 4 1
A file() 0 4 1
A vars() 0 19 3
A clear_vars() 0 5 1
A get_var() 0 4 2
A get_vars() 0 4 1
C helper() 0 58 12
A helpers() 0 4 1
A language() 0 5 1
A config() 0 4 1
C driver() 0 31 7
A add_package_path() 0 16 1
A get_package_paths() 0 4 2
B remove_package_path() 0 43 6
F _ci_load() 0 123 19
C _ci_load_library() 0 79 11
C _ci_load_stock_library() 0 72 10
F _ci_init_library() 0 89 15
F _ci_autoloader() 0 76 16
A _ci_object_to_array() 0 4 2
A _ci_get_component() 0 5 1
A _ci_prep_filename() 0 16 3

How to fix   Complexity   

Complex Class

Complex classes like CI_Loader often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use CI_Loader, and based on these observations, apply Extract Interface, too.

1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 51 and the first side effect is on line 38.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * CodeIgniter
4
 *
5
 * An open source application development framework for PHP
6
 *
7
 * This content is released under the MIT License (MIT)
8
 *
9
 * Copyright (c) 2014 - 2015, British Columbia Institute of Technology
10
 *
11
 * Permission is hereby granted, free of charge, to any person obtaining a copy
12
 * of this software and associated documentation files (the "Software"), to deal
13
 * in the Software without restriction, including without limitation the rights
14
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
 * copies of the Software, and to permit persons to whom the Software is
16
 * furnished to do so, subject to the following conditions:
17
 *
18
 * The above copyright notice and this permission notice shall be included in
19
 * all copies or substantial portions of the Software.
20
 *
21
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27
 * THE SOFTWARE.
28
 *
29
 * @package	CodeIgniter
30
 * @author	EllisLab Dev Team
31
 * @copyright	Copyright (c) 2008 - 2014, EllisLab, Inc. (http://ellislab.com/)
32
 * @copyright	Copyright (c) 2014 - 2015, British Columbia Institute of Technology (http://bcit.ca/)
33
 * @license	http://opensource.org/licenses/MIT	MIT License
34
 * @link	http://codeigniter.com
35
 * @since	Version 1.0.0
36
 * @filesource
37
 */
38
defined('BASEPATH') OR exit('No direct script access allowed');
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
39
40
/**
41
 * Loader Class (Modified by ci-phpunit-test)
42
 *
43
 * Loads framework components.
44
 *
45
 * @package		CodeIgniter
46
 * @subpackage	Libraries
47
 * @category	Loader
48
 * @author		EllisLab Dev Team
49
 * @link		http://codeigniter.com/user_guide/libraries/loader.html
50
 */
51
class CI_Loader {
0 ignored issues
show
Coding Style Compatibility introduced by
PSR1 recommends that each class must be in a namespace of at least one level to avoid collisions.

You can fix this by adding a namespace to your class:

namespace YourVendor;

class YourClass { }

When choosing a vendor namespace, try to pick something that is not too generic to avoid conflicts with other libraries.

Loading history...
52
53
	// All these are set automatically. Don't mess with them.
54
	/**
55
	 * Nesting level of the output buffering mechanism
56
	 *
57
	 * @var	int
58
	 */
59
	protected $_ci_ob_level;
60
61
	/**
62
	 * List of paths to load views from
63
	 *
64
	 * @var	array
65
	 */
66
	protected $_ci_view_paths =	array(VIEWPATH	=> TRUE);
67
68
	/**
69
	 * List of paths to load libraries from
70
	 *
71
	 * @var	array
72
	 */
73
	protected $_ci_library_paths =	array(APPPATH, BASEPATH);
74
75
	/**
76
	 * List of paths to load models from
77
	 *
78
	 * @var	array
79
	 */
80
	protected $_ci_model_paths =	array(APPPATH);
81
82
	/**
83
	 * List of paths to load helpers from
84
	 *
85
	 * @var	array
86
	 */
87
	protected $_ci_helper_paths =	array(APPPATH, BASEPATH);
88
89
	/**
90
	 * List of cached variables
91
	 *
92
	 * @var	array
93
	 */
94
	protected $_ci_cached_vars =	array();
95
96
	/**
97
	 * List of loaded classes
98
	 *
99
	 * @var	array
100
	 */
101
	protected $_ci_classes =	array();
102
103
	/**
104
	 * List of loaded models
105
	 *
106
	 * @var	array
107
	 */
108
	protected $_ci_models =	array();
109
110
	/**
111
	 * List of loaded helpers
112
	 *
113
	 * @var	array
114
	 */
115
	protected $_ci_helpers =	array();
116
117
	/**
118
	 * List of class name mappings
119
	 *
120
	 * @var	array
121
	 */
122
	protected $_ci_varmap =	array(
123
		'unit_test' => 'unit',
124
		'user_agent' => 'agent'
125
	);
126
127
	// --------------------------------------------------------------------
128
129
	/**
130
	 * Class constructor
131
	 *
132
	 * Sets component load paths, gets the initial output buffering level.
133
	 *
134
	 * @return	void
0 ignored issues
show
Comprehensibility Best Practice introduced by
Adding a @return annotation to constructors is generally not recommended as a constructor does not have a meaningful return value.

Adding a @return annotation to a constructor is not recommended, since a constructor does not have a meaningful return value.

Please refer to the PHP core documentation on constructors.

Loading history...
135
	 */
136
	public function __construct()
137
	{
138
		$this->_ci_ob_level = ob_get_level();
139
		$this->_ci_classes =& is_loaded();
140
141
		log_message('info', 'Loader Class Initialized');
142
	}
143
144
	// --------------------------------------------------------------------
145
146
	/**
147
	 * Initializer
148
	 *
149
	 * @todo	Figure out a way to move this to the constructor
150
	 *		without breaking *package_path*() methods.
151
	 * @uses	CI_Loader::_ci_autoloader()
152
	 * @used-by	CI_Controller::__construct()
153
	 * @return	void
154
	 */
155
	public function initialize()
156
	{
157
		$this->_ci_autoloader();
158
	}
159
160
	// --------------------------------------------------------------------
161
162
	/**
163
	 * Is Loaded
164
	 *
165
	 * A utility method to test if a class is in the self::$_ci_classes array.
166
	 *
167
	 * @used-by	Mainly used by Form Helper function _get_validation_object().
168
	 *
169
	 * @param 	string		$class	Class name to check for
170
	 * @return 	string|bool	Class object name if loaded or FALSE
171
	 */
172
	public function is_loaded($class)
173
	{
174
		return array_search(ucfirst($class), $this->_ci_classes, TRUE);
175
	}
176
177
	// --------------------------------------------------------------------
178
179
	/**
180
	 * Library Loader
181
	 *
182
	 * Loads and instantiates libraries.
183
	 * Designed to be called from application controllers.
184
	 *
185
	 * @param	string	$library	Library name
186
	 * @param	array	$params		Optional parameters to pass to the library class constructor
187
	 * @param	string	$object_name	An optional object name to assign to
188
	 * @return	object
189
	 */
190
	public function library($library, $params = NULL, $object_name = NULL)
191
	{
192
		if (empty($library))
193
		{
194
			return $this;
195
		}
196
		elseif (is_array($library))
197
		{
198
			foreach ($library as $key => $value)
199
			{
200
				if (is_int($key))
201
				{
202
					$this->library($value, $params);
203
				}
204
				else
205
				{
206
					$this->library($key, $params, $value);
207
				}
208
			}
209
210
			return $this;
211
		}
212
213
		if ($params !== NULL && ! is_array($params))
214
		{
215
			$params = NULL;
216
		}
217
218
		$this->_ci_load_library($library, $params, $object_name);
219
		return $this;
220
	}
221
222
	// --------------------------------------------------------------------
223
224
	/**
225
	 * Model Loader
226
	 *
227
	 * Loads and instantiates models.
228
	 *
229
	 * @param	string	$model		Model name
230
	 * @param	string	$name		An optional object name to assign to
231
	 * @param	bool	$db_conn	An optional database connection configuration to initialize
232
	 * @return	object
233
	 * 
234
	 * modified by ci-phpunit-test
235
	 */
236
	public function model($model, $name = '', $db_conn = FALSE)
237
	{
238
		if (empty($model))
239
		{
240
			return $this;
241
		}
242
		elseif (is_array($model))
243
		{
244
			foreach ($model as $key => $value)
245
			{
246
				is_int($key) ? $this->model($value, '', $db_conn) : $this->model($key, $value, $db_conn);
247
			}
248
249
			return $this;
250
		}
251
252
		$path = '';
253
254
		// Is the model in a sub-folder? If so, parse out the filename and path.
255
		if (($last_slash = strrpos($model, '/')) !== FALSE)
256
		{
257
			// The path is in front of the last slash
258
			$path = substr($model, 0, ++$last_slash);
259
260
			// And the model name behind it
261
			$model = substr($model, $last_slash);
262
		}
263
264
		if (empty($name))
265
		{
266
			$name = $model;
267
		}
268
269
		if (in_array($name, $this->_ci_models, TRUE))
270
		{
271
			return $this;
272
		}
273
274
		$CI =& get_instance();
275
		if (isset($CI->$name))
276
		{
277
			show_error('The model name you are loading is the name of a resource that is already being used: '.$name);
278
		}
279
280
		if ($db_conn !== FALSE && ! class_exists('CI_DB', FALSE))
281
		{
282
			if ($db_conn === TRUE)
283
			{
284
				$db_conn = '';
285
			}
286
287
			$this->database($db_conn, FALSE, TRUE);
288
		}
289
290
//		if ( ! class_exists('CI_Model', FALSE))
0 ignored issues
show
Unused Code Comprehensibility introduced by
56% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
291
//		{
292
			load_class('Model', 'core');
293
//		}
294
295
		$model = ucfirst(strtolower($model));
296
297
		foreach ($this->_ci_model_paths as $mod_path)
298
		{
299
			if ( ! file_exists($mod_path.'models/'.$path.$model.'.php'))
300
			{
301
				continue;
302
			}
303
304
			require_once($mod_path.'models/'.$path.$model.'.php');
305
306
			$this->_ci_models[] = $name;
307
			$CI->$name = new $model();
308
			return $this;
309
		}
310
311
		// couldn't find the model
312
		show_error('Unable to locate the model you have specified: '.$model);
313
	}
314
315
	// --------------------------------------------------------------------
316
317
	/**
318
	 * Database Loader
319
	 *
320
	 * @param	mixed	$params		Database configuration options
321
	 * @param	bool	$return 	Whether to return the database object
322
	 * @param	bool	$query_builder	Whether to enable Query Builder
323
	 *					(overrides the configuration setting)
324
	 *
325
	 * @return	object|bool	Database object if $return is set to TRUE,
326
	 *					FALSE on failure, CI_Loader instance in any other case
327
	 */
328
	public function database($params = '', $return = FALSE, $query_builder = NULL)
329
	{
330
		// Grab the super object
331
		$CI =& get_instance();
332
333
		// Do we even need to load the database class?
334
		if ($return === FALSE && $query_builder === NULL && isset($CI->db) && is_object($CI->db) && ! empty($CI->db->conn_id))
335
		{
336
			return FALSE;
337
		}
338
339
		require_once(BASEPATH.'database/DB.php');
340
341
		if ($return === TRUE)
342
		{
343
			return DB($params, $query_builder);
344
		}
345
346
		// Initialize the db variable. Needed to prevent
347
		// reference errors with some configurations
348
		$CI->db = '';
349
350
		// Load the DB class
351
		$CI->db =& DB($params, $query_builder);
352
		return $this;
353
	}
354
355
	// --------------------------------------------------------------------
356
357
	/**
358
	 * Load the Database Utilities Class
359
	 *
360
	 * @param	object	$db	Database object
361
	 * @param	bool	$return	Whether to return the DB Utilities class object or not
362
	 * @return	object
363
	 */
364
	public function dbutil($db = NULL, $return = FALSE)
365
	{
366
		$CI =& get_instance();
367
368
		if ( ! is_object($db) OR ! ($db instanceof CI_DB))
0 ignored issues
show
Bug introduced by
The class CI_DB does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
369
		{
370
			class_exists('CI_DB', FALSE) OR $this->database();
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
371
			$db =& $CI->db;
372
		}
373
374
		require_once(BASEPATH.'database/DB_utility.php');
375
		require_once(BASEPATH.'database/drivers/'.$db->dbdriver.'/'.$db->dbdriver.'_utility.php');
376
		$class = 'CI_DB_'.$db->dbdriver.'_utility';
377
378
		if ($return === TRUE)
379
		{
380
			return new $class($db);
381
		}
382
383
		$CI->dbutil = new $class($db);
384
		return $this;
385
	}
386
387
	// --------------------------------------------------------------------
388
389
	/**
390
	 * Load the Database Forge Class
391
	 *
392
	 * @param	object	$db	Database object
393
	 * @param	bool	$return	Whether to return the DB Forge class object or not
394
	 * @return	object
395
	 */
396
	public function dbforge($db = NULL, $return = FALSE)
397
	{
398
		$CI =& get_instance();
399
		if ( ! is_object($db) OR ! ($db instanceof CI_DB))
0 ignored issues
show
Bug introduced by
The class CI_DB does not exist. Did you forget a USE statement, or did you not list all dependencies?

This error could be the result of:

1. Missing dependencies

PHP Analyzer uses your composer.json file (if available) to determine the dependencies of your project and to determine all the available classes and functions. It expects the composer.json to be in the root folder of your repository.

Are you sure this class is defined by one of your dependencies, or did you maybe not list a dependency in either the require or require-dev section?

2. Missing use statement

PHP does not complain about undefined classes in ìnstanceof checks. For example, the following PHP code will work perfectly fine:

if ($x instanceof DoesNotExist) {
    // Do something.
}

If you have not tested against this specific condition, such errors might go unnoticed.

Loading history...
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
400
		{
401
			class_exists('CI_DB', FALSE) OR $this->database();
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as or instead of || is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
402
			$db =& $CI->db;
403
		}
404
405
		require_once(BASEPATH.'database/DB_forge.php');
406
		require_once(BASEPATH.'database/drivers/'.$db->dbdriver.'/'.$db->dbdriver.'_forge.php');
407
408
		if ( ! empty($db->subdriver))
409
		{
410
			$driver_path = BASEPATH.'database/drivers/'.$db->dbdriver.'/subdrivers/'.$db->dbdriver.'_'.$db->subdriver.'_forge.php';
411
			if (file_exists($driver_path))
412
			{
413
				require_once($driver_path);
414
				$class = 'CI_DB_'.$db->dbdriver.'_'.$db->subdriver.'_forge';
415
			}
416
		}
417
		else
418
		{
419
			$class = 'CI_DB_'.$db->dbdriver.'_forge';
420
		}
421
422
		if ($return === TRUE)
423
		{
424
			return new $class($db);
0 ignored issues
show
Bug introduced by
The variable $class does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
425
		}
426
427
		$CI->dbforge = new $class($db);
428
		return $this;
429
	}
430
431
	// --------------------------------------------------------------------
432
433
	/**
434
	 * View Loader
435
	 *
436
	 * Loads "view" files.
437
	 *
438
	 * @param	string	$view	View name
439
	 * @param	array	$vars	An associative array of data
440
	 *				to be extracted for use in the view
441
	 * @param	bool	$return	Whether to return the view output
442
	 *				or leave it to the Output class
443
	 * @return	object|string
444
	 */
445
	public function view($view, $vars = array(), $return = FALSE)
446
	{
447
		return $this->_ci_load(array('_ci_view' => $view, '_ci_vars' => $this->_ci_object_to_array($vars), '_ci_return' => $return));
0 ignored issues
show
Documentation introduced by
$vars is of type array, but the function expects a object.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
448
	}
449
450
	// --------------------------------------------------------------------
451
452
	/**
453
	 * Generic File Loader
454
	 *
455
	 * @param	string	$path	File path
456
	 * @param	bool	$return	Whether to return the file output
457
	 * @return	object|string
458
	 */
459
	public function file($path, $return = FALSE)
460
	{
461
		return $this->_ci_load(array('_ci_path' => $path, '_ci_return' => $return));
462
	}
463
464
	// --------------------------------------------------------------------
465
466
	/**
467
	 * Set Variables
468
	 *
469
	 * Once variables are set they become available within
470
	 * the controller class and its "view" files.
471
	 *
472
	 * @param	array|object|string	$vars
473
	 *					An associative array or object containing values
474
	 *					to be set, or a value's name if string
475
	 * @param 	string	$val	Value to set, only used if $vars is a string
476
	 * @return	object
477
	 */
478
	public function vars($vars, $val = '')
479
	{
480
		if (is_string($vars))
481
		{
482
			$vars = array($vars => $val);
483
		}
484
485
		$vars = $this->_ci_object_to_array($vars);
0 ignored issues
show
Bug introduced by
It seems like $vars defined by $this->_ci_object_to_array($vars) on line 485 can also be of type array; however, CI_Loader::_ci_object_to_array() does only seem to accept object, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
486
487
		if (is_array($vars) && count($vars) > 0)
488
		{
489
			foreach ($vars as $key => $val)
490
			{
491
				$this->_ci_cached_vars[$key] = $val;
492
			}
493
		}
494
495
		return $this;
496
	}
497
498
	// --------------------------------------------------------------------
499
500
	/**
501
	 * Clear Cached Variables
502
	 *
503
	 * Clears the cached variables.
504
	 *
505
	 * @return  object
506
	 */
507
	public function clear_vars()
508
	{
509
		$this->_ci_cached_vars = array();
510
		return $this;
511
	}
512
513
	// --------------------------------------------------------------------
514
515
	/**
516
	 * Get Variable
517
	 *
518
	 * Check if a variable is set and retrieve it.
519
	 *
520
	 * @param	string	$key	Variable name
521
	 * @return	mixed	The variable or NULL if not found
522
	 */
523
	public function get_var($key)
524
	{
525
		return isset($this->_ci_cached_vars[$key]) ? $this->_ci_cached_vars[$key] : NULL;
526
	}
527
528
	// --------------------------------------------------------------------
529
530
	/**
531
	 * Get Variables
532
	 *
533
	 * Retrieves all loaded variables.
534
	 *
535
	 * @return	array
536
	 */
537
	public function get_vars()
538
	{
539
		return $this->_ci_cached_vars;
540
	}
541
542
	// --------------------------------------------------------------------
543
544
	/**
545
	 * Helper Loader
546
	 *
547
	 * @param	string|string[]	$helpers	Helper name(s)
548
	 * @return	object
549
	 */
550
	public function helper($helpers = array())
551
	{
552
		foreach ($this->_ci_prep_filename($helpers, '_helper') as $helper)
553
		{
554
			if (isset($this->_ci_helpers[$helper]))
555
			{
556
				continue;
557
			}
558
559
			// Is this a helper extension request?
560
			$ext_helper = config_item('subclass_prefix').$helper;
561
			$ext_loaded = FALSE;
562
			foreach ($this->_ci_helper_paths as $path)
563
			{
564
				if (file_exists($path.'helpers/'.$ext_helper.'.php'))
565
				{
566
					include_once($path.'helpers/'.$ext_helper.'.php');
567
					$ext_loaded = TRUE;
568
				}
569
			}
570
571
			// If we have loaded extensions - check if the base one is here
572
			if ($ext_loaded === TRUE)
573
			{
574
				$base_helper = BASEPATH.'helpers/'.$helper.'.php';
575
				if ( ! file_exists($base_helper))
576
				{
577
					show_error('Unable to load the requested file: helpers/'.$helper.'.php');
578
				}
579
580
				include_once($base_helper);
581
				$this->_ci_helpers[$helper] = TRUE;
582
				log_message('info', 'Helper loaded: '.$helper);
583
				continue;
584
			}
585
586
			// No extensions found ... try loading regular helpers and/or overrides
587
			foreach ($this->_ci_helper_paths as $path)
588
			{
589
				if (file_exists($path.'helpers/'.$helper.'.php'))
590
				{
591
					include_once($path.'helpers/'.$helper.'.php');
592
593
					$this->_ci_helpers[$helper] = TRUE;
594
					log_message('info', 'Helper loaded: '.$helper);
595
					break;
596
				}
597
			}
598
599
			// unable to load the helper
600
			if ( ! isset($this->_ci_helpers[$helper]))
601
			{
602
				show_error('Unable to load the requested file: helpers/'.$helper.'.php');
603
			}
604
		}
605
606
		return $this;
607
	}
608
609
	// --------------------------------------------------------------------
610
611
	/**
612
	 * Load Helpers
613
	 *
614
	 * An alias for the helper() method in case the developer has
615
	 * written the plural form of it.
616
	 *
617
	 * @uses	CI_Loader::helper()
618
	 * @param	string|string[]	$helpers	Helper name(s)
619
	 * @return	object
620
	 */
621
	public function helpers($helpers = array())
622
	{
623
		return $this->helper($helpers);
624
	}
625
626
	// --------------------------------------------------------------------
627
628
	/**
629
	 * Language Loader
630
	 *
631
	 * Loads language files.
632
	 *
633
	 * @param	string|string[]	$files	List of language file names to load
634
	 * @param	string		Language name
635
	 * @return	object
636
	 */
637
	public function language($files, $lang = '')
638
	{
639
		get_instance()->lang->load($files, $lang);
640
		return $this;
641
	}
642
643
	// --------------------------------------------------------------------
644
645
	/**
646
	 * Config Loader
647
	 *
648
	 * Loads a config file (an alias for CI_Config::load()).
649
	 *
650
	 * @uses	CI_Config::load()
651
	 * @param	string	$file			Configuration file name
652
	 * @param	bool	$use_sections		Whether configuration values should be loaded into their own section
653
	 * @param	bool	$fail_gracefully	Whether to just return FALSE or display an error message
654
	 * @return	bool	TRUE if the file was loaded correctly or FALSE on failure
655
	 */
656
	public function config($file, $use_sections = FALSE, $fail_gracefully = FALSE)
657
	{
658
		return get_instance()->config->load($file, $use_sections, $fail_gracefully);
659
	}
660
661
	// --------------------------------------------------------------------
662
663
	/**
664
	 * Driver Loader
665
	 *
666
	 * Loads a driver library.
667
	 *
668
	 * @param	string|string[]	$library	Driver name(s)
669
	 * @param	array		$params		Optional parameters to pass to the driver
670
	 * @param	string		$object_name	An optional object name to assign to
671
	 *
672
	 * @return	object|bool	Object or FALSE on failure if $library is a string
673
	 *				and $object_name is set. CI_Loader instance otherwise.
674
	 */
675
	public function driver($library, $params = NULL, $object_name = NULL)
676
	{
677
		if (is_array($library))
678
		{
679
			foreach ($library as $driver)
680
			{
681
				$this->driver($driver);
682
			}
683
684
			return $this;
685
		}
686
		elseif (empty($library))
687
		{
688
			return FALSE;
689
		}
690
691
		if ( ! class_exists('CI_Driver_Library', FALSE))
692
		{
693
			// We aren't instantiating an object here, just making the base class available
694
			require BASEPATH.'libraries/Driver.php';
695
		}
696
697
		// We can save the loader some time since Drivers will *always* be in a subfolder,
698
		// and typically identically named to the library
699
		if ( ! strpos($library, '/'))
700
		{
701
			$library = ucfirst($library).'/'.$library;
702
		}
703
704
		return $this->library($library, $params, $object_name);
705
	}
706
707
	// --------------------------------------------------------------------
708
709
	/**
710
	 * Add Package Path
711
	 *
712
	 * Prepends a parent path to the library, model, helper and config
713
	 * path arrays.
714
	 *
715
	 * @see	CI_Loader::$_ci_library_paths
716
	 * @see	CI_Loader::$_ci_model_paths
717
	 * @see CI_Loader::$_ci_helper_paths
718
	 * @see CI_Config::$_config_paths
719
	 *
720
	 * @param	string	$path		Path to add
721
	 * @param 	bool	$view_cascade	(default: TRUE)
722
	 * @return	object
723
	 */
724
	public function add_package_path($path, $view_cascade = TRUE)
725
	{
726
		$path = rtrim($path, '/').'/';
727
728
		array_unshift($this->_ci_library_paths, $path);
729
		array_unshift($this->_ci_model_paths, $path);
730
		array_unshift($this->_ci_helper_paths, $path);
731
732
		$this->_ci_view_paths = array($path.'views/' => $view_cascade) + $this->_ci_view_paths;
733
734
		// Add config file path
735
		$config =& $this->_ci_get_component('config');
736
		$config->_config_paths[] = $path;
737
738
		return $this;
739
	}
740
741
	// --------------------------------------------------------------------
742
743
	/**
744
	 * Get Package Paths
745
	 *
746
	 * Return a list of all package paths.
747
	 *
748
	 * @param	bool	$include_base	Whether to include BASEPATH (default: FALSE)
749
	 * @return	array
750
	 */
751
	public function get_package_paths($include_base = FALSE)
752
	{
753
		return ($include_base === TRUE) ? $this->_ci_library_paths : $this->_ci_model_paths;
754
	}
755
756
	// --------------------------------------------------------------------
757
758
	/**
759
	 * Remove Package Path
760
	 *
761
	 * Remove a path from the library, model, helper and/or config
762
	 * path arrays if it exists. If no path is provided, the most recently
763
	 * added path will be removed removed.
764
	 *
765
	 * @param	string	$path	Path to remove
766
	 * @return	object
767
	 */
768
	public function remove_package_path($path = '')
769
	{
770
		$config =& $this->_ci_get_component('config');
771
772
		if ($path === '')
773
		{
774
			array_shift($this->_ci_library_paths);
775
			array_shift($this->_ci_model_paths);
776
			array_shift($this->_ci_helper_paths);
777
			array_shift($this->_ci_view_paths);
778
			array_pop($config->_config_paths);
779
		}
780
		else
781
		{
782
			$path = rtrim($path, '/').'/';
783
			foreach (array('_ci_library_paths', '_ci_model_paths', '_ci_helper_paths') as $var)
784
			{
785
				if (($key = array_search($path, $this->{$var})) !== FALSE)
786
				{
787
					unset($this->{$var}[$key]);
788
				}
789
			}
790
791
			if (isset($this->_ci_view_paths[$path.'views/']))
792
			{
793
				unset($this->_ci_view_paths[$path.'views/']);
794
			}
795
796
			if (($key = array_search($path, $config->_config_paths)) !== FALSE)
797
			{
798
				unset($config->_config_paths[$key]);
799
			}
800
		}
801
802
		// make sure the application default paths are still in the array
803
		$this->_ci_library_paths = array_unique(array_merge($this->_ci_library_paths, array(APPPATH, BASEPATH)));
804
		$this->_ci_helper_paths = array_unique(array_merge($this->_ci_helper_paths, array(APPPATH, BASEPATH)));
805
		$this->_ci_model_paths = array_unique(array_merge($this->_ci_model_paths, array(APPPATH)));
806
		$this->_ci_view_paths = array_merge($this->_ci_view_paths, array(APPPATH.'views/' => TRUE));
807
		$config->_config_paths = array_unique(array_merge($config->_config_paths, array(APPPATH)));
808
809
		return $this;
810
	}
811
812
	// --------------------------------------------------------------------
813
814
	/**
815
	 * Internal CI Data Loader
816
	 *
817
	 * Used to load views and files.
818
	 *
819
	 * Variables are prefixed with _ci_ to avoid symbol collision with
820
	 * variables made available to view files.
821
	 *
822
	 * @used-by	CI_Loader::view()
823
	 * @used-by	CI_Loader::file()
824
	 * @param	array	$_ci_data	Data to load
825
	 * @return	object
826
	 */
827
	protected function _ci_load($_ci_data)
828
	{
829
		// Set the default data variables
830
		foreach (array('_ci_view', '_ci_vars', '_ci_path', '_ci_return') as $_ci_val)
831
		{
832
			$$_ci_val = isset($_ci_data[$_ci_val]) ? $_ci_data[$_ci_val] : FALSE;
833
		}
834
835
		$file_exists = FALSE;
836
837
		// Set the path to the requested file
838
		if (is_string($_ci_path) && $_ci_path !== '')
0 ignored issues
show
Bug introduced by
The variable $_ci_path seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
839
		{
840
			$_ci_x = explode('/', $_ci_path);
0 ignored issues
show
Bug introduced by
The variable $_ci_path seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
841
			$_ci_file = end($_ci_x);
842
		}
843
		else
844
		{
845
			$_ci_ext = pathinfo($_ci_view, PATHINFO_EXTENSION);
0 ignored issues
show
Bug introduced by
The variable $_ci_view does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
846
			$_ci_file = ($_ci_ext === '') ? $_ci_view.'.php' : $_ci_view;
847
848
			foreach ($this->_ci_view_paths as $_ci_view_file => $cascade)
849
			{
850
				if (file_exists($_ci_view_file.$_ci_file))
851
				{
852
					$_ci_path = $_ci_view_file.$_ci_file;
853
					$file_exists = TRUE;
854
					break;
855
				}
856
857
				if ( ! $cascade)
858
				{
859
					break;
860
				}
861
			}
862
		}
863
864
		if ( ! $file_exists && ! file_exists($_ci_path))
0 ignored issues
show
Bug introduced by
The variable $_ci_path does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
865
		{
866
			show_error('Unable to load the requested file: '.$_ci_file);
867
		}
868
869
		// This allows anything loaded using $this->load (views, files, etc.)
870
		// to become accessible from within the Controller and Model functions.
871
		$_ci_CI =& get_instance();
872
		foreach (get_object_vars($_ci_CI) as $_ci_key => $_ci_var)
873
		{
874
			if ( ! isset($this->$_ci_key))
875
			{
876
				$this->$_ci_key =& $_ci_CI->$_ci_key;
877
			}
878
		}
879
880
		/*
881
		 * Extract and cache variables
882
		 *
883
		 * You can either set variables using the dedicated $this->load->vars()
884
		 * function or via the second parameter of this function. We'll merge
885
		 * the two types and cache them so that views that are embedded within
886
		 * other views can have access to these variables.
887
		 */
888
		if (is_array($_ci_vars))
889
		{
890
			$this->_ci_cached_vars = array_merge($this->_ci_cached_vars, $_ci_vars);
0 ignored issues
show
Bug introduced by
The variable $_ci_vars does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
891
		}
892
		extract($this->_ci_cached_vars);
893
894
		/*
895
		 * Buffer the output
896
		 *
897
		 * We buffer the output for two reasons:
898
		 * 1. Speed. You get a significant speed boost.
899
		 * 2. So that the final rendered template can be post-processed by
900
		 *	the output class. Why do we need post processing? For one thing,
901
		 *	in order to show the elapsed page load time. Unless we can
902
		 *	intercept the content right before it's sent to the browser and
903
		 *	then stop the timer it won't be accurate.
904
		 */
905
		ob_start();
906
907
		// If the PHP installation does not support short tags we'll
908
		// do a little string replacement, changing the short tags
909
		// to standard PHP echo statements.
910
		if ( ! is_php('5.4') && ! ini_get('short_open_tag') && config_item('rewrite_short_tags') === TRUE && function_usable('eval'))
911
		{
912
			echo eval('?>'.preg_replace('/;*\s*\?>/', '; ?>', str_replace('<?=', '<?php echo ', file_get_contents($_ci_path))));
0 ignored issues
show
Coding Style introduced by
It is generally not recommended to use eval unless absolutely required.

On one hand, eval might be exploited by malicious users if they somehow manage to inject dynamic content. On the other hand, with the emergence of faster PHP runtimes like the HHVM, eval prevents some optimization that they perform.

Loading history...
913
		}
914
		else
915
		{
916
			include($_ci_path); // include() vs include_once() allows for multiple views with the same name
917
		}
918
919
		log_message('info', 'File loaded: '.$_ci_path);
920
921
		// Return the file data if requested
922
		if ($_ci_return === TRUE)
923
		{
924
			$buffer = ob_get_contents();
925
			@ob_end_clean();
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
926
			return $buffer;
927
		}
928
929
		/*
930
		 * Flush the buffer... or buff the flusher?
931
		 *
932
		 * In order to permit views to be nested within
933
		 * other views, we need to flush the content back out whenever
934
		 * we are beyond the first level of output buffering so that
935
		 * it can be seen and included properly by the first included
936
		 * template and any subsequent ones. Oy!
937
		 */
938
		if (ob_get_level() > $this->_ci_ob_level + 1)
939
		{
940
			ob_end_flush();
941
		}
942
		else
943
		{
944
			$_ci_CI->output->append_output(ob_get_contents());
945
			@ob_end_clean();
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
946
		}
947
948
		return $this;
949
	}
950
951
	// --------------------------------------------------------------------
952
953
	/**
954
	 * Internal CI Library Loader
955
	 *
956
	 * @used-by	CI_Loader::library()
957
	 * @uses	CI_Loader::_ci_init_library()
958
	 *
959
	 * @param	string	$class		Class name to load
960
	 * @param	mixed	$params		Optional parameters to pass to the class constructor
961
	 * @param	string	$object_name	Optional object name to assign to
962
	 * @return	void
963
	 * 
964
	 * modified by ci-phpunit-test
965
	 */
966
	protected function _ci_load_library($class, $params = NULL, $object_name = NULL)
967
	{
968
		// Get the class name, and while we're at it trim any slashes.
969
		// The directory path can be included as part of the class name,
970
		// but we don't want a leading slash
971
		$class = str_replace('.php', '', trim($class, '/'));
972
973
		// Was the path included with the class name?
974
		// We look for a slash to determine this
975
		if (($last_slash = strrpos($class, '/')) !== FALSE)
976
		{
977
			// Extract the path
978
			$subdir = substr($class, 0, ++$last_slash);
979
980
			// Get the filename from the path
981
			$class = substr($class, $last_slash);
982
		}
983
		else
984
		{
985
			$subdir = '';
986
		}
987
988
		$class = ucfirst($class);
989
990
		// Is this a stock library? There are a few special conditions if so ...
991
		if (file_exists(BASEPATH.'libraries/'.$subdir.$class.'.php'))
992
		{
993
			return $this->_ci_load_stock_library($class, $subdir, $params, $object_name);
994
		}
995
996
		// Let's search for the requested library file and load it.
997
		foreach ($this->_ci_library_paths as $path)
998
		{
999
			// BASEPATH has already been checked for
1000
			if ($path === BASEPATH)
1001
			{
1002
				continue;
1003
			}
1004
1005
			$filepath = $path.'libraries/'.$subdir.$class.'.php';
1006
1007
			// Safety: Was the class already loaded by a previous call?
1008
//			if (class_exists($class, FALSE))
1009
//			{
1010
				// Before we deem this to be a duplicate request, let's see
1011
				// if a custom object name is being supplied. If so, we'll
1012
				// return a new instance of the object
1013
				if ($object_name !== NULL)
1014
				{
1015
					$CI =& get_instance();
1016
					if ( ! isset($CI->$object_name))
1017
					{
1018
						return $this->_ci_init_library($class, '', $params, $object_name);
1019
					}
1020
				}
1021
1022
//				log_message('debug', $class.' class already loaded. Second attempt ignored.');
0 ignored issues
show
Unused Code Comprehensibility introduced by
56% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1023
//				return;
1024
//			}
1025
			// Does the file exist? No? Bummer...
1026
			if ( ! file_exists($filepath))
1027
			{
1028
				continue;
1029
			}
1030
1031
			include_once($filepath);
1032
			return $this->_ci_init_library($class, '', $params, $object_name);
1033
		}
1034
1035
		// One last attempt. Maybe the library is in a subdirectory, but it wasn't specified?
1036
		if ($subdir === '')
1037
		{
1038
			return $this->_ci_load_library($class.'/'.$class, $params, $object_name);
1039
		}
1040
1041
		// If we got this far we were unable to find the requested class.
1042
		log_message('error', 'Unable to load the requested class: '.$class);
1043
		show_error('Unable to load the requested class: '.$class);
1044
	}
1045
1046
	// --------------------------------------------------------------------
1047
1048
	/**
1049
	 * Internal CI Stock Library Loader
1050
	 *
1051
	 * @used-by	CI_Loader::_ci_load_library()
1052
	 * @uses	CI_Loader::_ci_init_library()
1053
	 *
1054
	 * @param	string	$library	Library name to load
0 ignored issues
show
Documentation introduced by
There is no parameter named $library. Did you maybe mean $library_name?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
1055
	 * @param	string	$file_path	Path to the library filename, relative to libraries/
1056
	 * @param	mixed	$params		Optional parameters to pass to the class constructor
1057
	 * @param	string	$object_name	Optional object name to assign to
1058
	 * @return	void
1059
	 * 
1060
	 * modified by ci-phpunit-test
1061
	 */
1062
	protected function _ci_load_stock_library($library_name, $file_path, $params, $object_name)
1063
	{
1064
		$prefix = 'CI_';
1065
1066
//		if (class_exists($prefix.$library_name, FALSE))
0 ignored issues
show
Unused Code Comprehensibility introduced by
65% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1067
		{
1068
			if (class_exists(config_item('subclass_prefix').$library_name, FALSE))
1069
			{
1070
				$prefix = config_item('subclass_prefix');
1071
			}
1072
1073
			// Before we deem this to be a duplicate request, let's see
1074
			// if a custom object name is being supplied. If so, we'll
1075
			// return a new instance of the object
1076
			if ($object_name !== NULL)
1077
			{
1078
				$CI =& get_instance();
1079
				if ( ! isset($CI->$object_name))
1080
				{
1081
					return $this->_ci_init_library($library_name, $prefix, $params, $object_name);
1082
				}
1083
			}
1084
1085
//			log_message('debug', $library_name.' class already loaded. Second attempt ignored.');
0 ignored issues
show
Unused Code Comprehensibility introduced by
60% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1086
//			return;
1087
		}
1088
1089
		$paths = $this->_ci_library_paths;
1090
		array_pop($paths); // BASEPATH
1091
		array_pop($paths); // APPPATH (needs to be the first path checked)
1092
		array_unshift($paths, APPPATH);
1093
1094
		foreach ($paths as $path)
1095
		{
1096
			if (file_exists($path = $path.'libraries/'.$file_path.$library_name.'.php'))
1097
			{
1098
				// Override
1099
				include_once($path);
1100
//				if (class_exists($prefix.$library_name, FALSE))
0 ignored issues
show
Unused Code Comprehensibility introduced by
65% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1101
				{
1102
					return $this->_ci_init_library($library_name, $prefix, $params, $object_name);
1103
				}
1104
//				else
0 ignored issues
show
Unused Code Comprehensibility introduced by
50% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
1105
//				{
1106
//					log_message('debug', $path.' exists, but does not declare '.$prefix.$library_name);
1107
//				}
1108
			}
1109
		}
1110
1111
		include_once(BASEPATH.'libraries/'.$file_path.$library_name.'.php');
1112
1113
		// Check for extensions
1114
		$subclass = config_item('subclass_prefix').$library_name;
1115
		foreach ($paths as $path)
1116
		{
1117
			if (file_exists($path = $path.'libraries/'.$file_path.$subclass.'.php'))
1118
			{
1119
				include_once($path);
1120
				if (class_exists($subclass, FALSE))
1121
				{
1122
					$prefix = config_item('subclass_prefix');
1123
					break;
1124
				}
1125
				else
1126
				{
1127
					log_message('debug', APPPATH.'libraries/'.$file_path.$subclass.'.php exists, but does not declare '.$subclass);
1128
				}
1129
			}
1130
		}
1131
1132
		return $this->_ci_init_library($library_name, $prefix, $params, $object_name);
1133
	}
1134
1135
	// --------------------------------------------------------------------
1136
1137
	/**
1138
	 * Internal CI Library Instantiator
1139
	 *
1140
	 * @used-by	CI_Loader::_ci_load_stock_library()
1141
	 * @used-by	CI_Loader::_ci_load_library()
1142
	 *
1143
	 * @param	string		$class		Class name
1144
	 * @param	string		$prefix		Class name prefix
1145
	 * @param	array|null|bool	$config		Optional configuration to pass to the class constructor:
1146
	 *						FALSE to skip;
1147
	 *						NULL to search in config paths;
1148
	 *						array containing configuration data
1149
	 * @param	string		$object_name	Optional object name to assign to
1150
	 * @return	void
1151
	 */
1152
	protected function _ci_init_library($class, $prefix, $config = FALSE, $object_name = NULL)
1153
	{
1154
		// Is there an associated config file for this class? Note: these should always be lowercase
1155
		if ($config === NULL)
1156
		{
1157
			// Fetch the config paths containing any package paths
1158
			$config_component = $this->_ci_get_component('config');
1159
1160
			if (is_array($config_component->_config_paths))
1161
			{
1162
				$found = FALSE;
1163
				foreach ($config_component->_config_paths as $path)
1164
				{
1165
					// We test for both uppercase and lowercase, for servers that
1166
					// are case-sensitive with regard to file names. Load global first,
1167
					// override with environment next
1168
					if (file_exists($path.'config/'.strtolower($class).'.php'))
1169
					{
1170
						include($path.'config/'.strtolower($class).'.php');
1171
						$found = TRUE;
1172
					}
1173
					elseif (file_exists($path.'config/'.ucfirst(strtolower($class)).'.php'))
1174
					{
1175
						include($path.'config/'.ucfirst(strtolower($class)).'.php');
1176
						$found = TRUE;
1177
					}
1178
1179
					if (file_exists($path.'config/'.ENVIRONMENT.'/'.strtolower($class).'.php'))
1180
					{
1181
						include($path.'config/'.ENVIRONMENT.'/'.strtolower($class).'.php');
1182
						$found = TRUE;
1183
					}
1184
					elseif (file_exists($path.'config/'.ENVIRONMENT.'/'.ucfirst(strtolower($class)).'.php'))
1185
					{
1186
						include($path.'config/'.ENVIRONMENT.'/'.ucfirst(strtolower($class)).'.php');
1187
						$found = TRUE;
1188
					}
1189
1190
					// Break on the first found configuration, thus package
1191
					// files are not overridden by default paths
1192
					if ($found === TRUE)
1193
					{
1194
						break;
1195
					}
1196
				}
1197
			}
1198
		}
1199
1200
		$class_name = $prefix.$class;
1201
1202
		// Is the class name valid?
1203
		if ( ! class_exists($class_name, FALSE))
1204
		{
1205
			log_message('error', 'Non-existent class: '.$class_name);
1206
			show_error('Non-existent class: '.$class_name);
1207
		}
1208
1209
		// Set the variable name we will assign the class to
1210
		// Was a custom class name supplied? If so we'll use it
1211
		if (empty($object_name))
1212
		{
1213
			$object_name = strtolower($class);
1214
			if (isset($this->_ci_varmap[$object_name]))
1215
			{
1216
				$object_name = $this->_ci_varmap[$object_name];
1217
			}
1218
		}
1219
1220
		// Don't overwrite existing properties
1221
		$CI =& get_instance();
1222
		if (isset($CI->$object_name))
1223
		{
1224
			if ($CI->$object_name instanceof $class_name)
1225
			{
1226
				log_message('debug', $class_name." has already been instantiated as '".$object_name."'. Second attempt aborted.");
1227
				return;
1228
			}
1229
1230
			show_error("Resource '".$object_name."' already exists and is not a ".$class_name." instance.");
1231
		}
1232
1233
		// Save the class name and object name
1234
		$this->_ci_classes[$object_name] = $class;
1235
1236
		// Instantiate the class
1237
		$CI->$object_name = isset($config)
1238
			? new $class_name($config)
1239
			: new $class_name();
1240
	}
1241
1242
	// --------------------------------------------------------------------
1243
1244
	/**
1245
	 * CI Autoloader
1246
	 *
1247
	 * Loads component listed in the config/autoload.php file.
1248
	 *
1249
	 * @used-by	CI_Loader::initialize()
1250
	 * @return	void
1251
	 */
1252
	protected function _ci_autoloader()
1253
	{
1254
		if (file_exists(APPPATH.'config/autoload.php'))
1255
		{
1256
			include(APPPATH.'config/autoload.php');
1257
		}
1258
1259
		if (file_exists(APPPATH.'config/'.ENVIRONMENT.'/autoload.php'))
1260
		{
1261
			include(APPPATH.'config/'.ENVIRONMENT.'/autoload.php');
1262
		}
1263
1264
		if ( ! isset($autoload))
0 ignored issues
show
Bug introduced by
The variable $autoload seems only to be defined at a later point. As such the call to isset() seems to always evaluate to false.

This check marks calls to isset(...) or empty(...) that are found before the variable itself is defined. These will always have the same result.

This is likely the result of code being shifted around. Consider removing these calls.

Loading history...
1265
		{
1266
			return;
1267
		}
1268
1269
		// Autoload packages
1270
		if (isset($autoload['packages']))
1271
		{
1272
			foreach ($autoload['packages'] as $package_path)
1273
			{
1274
				$this->add_package_path($package_path);
1275
			}
1276
		}
1277
1278
		// Load any custom config file
1279
		if (count($autoload['config']) > 0)
1280
		{
1281
			foreach ($autoload['config'] as $val)
1282
			{
1283
				$this->config($val);
1284
			}
1285
		}
1286
1287
		// Autoload helpers and languages
1288
		foreach (array('helper', 'language') as $type)
1289
		{
1290
			if (isset($autoload[$type]) && count($autoload[$type]) > 0)
1291
			{
1292
				$this->$type($autoload[$type]);
1293
			}
1294
		}
1295
1296
		// Autoload drivers
1297
		if (isset($autoload['drivers']))
1298
		{
1299
			foreach ($autoload['drivers'] as $item)
1300
			{
1301
				$this->driver($item);
1302
			}
1303
		}
1304
1305
		// Load libraries
1306
		if (isset($autoload['libraries']) && count($autoload['libraries']) > 0)
1307
		{
1308
			// Load the database driver.
1309
			if (in_array('database', $autoload['libraries']))
1310
			{
1311
				$this->database();
1312
				$autoload['libraries'] = array_diff($autoload['libraries'], array('database'));
1313
			}
1314
1315
			// Load all other libraries
1316
			foreach ($autoload['libraries'] as $item)
1317
			{
1318
				$this->library($item);
1319
			}
1320
		}
1321
1322
		// Autoload models
1323
		if (isset($autoload['model']))
1324
		{
1325
			$this->model($autoload['model']);
0 ignored issues
show
Documentation introduced by
$autoload['model'] is of type array, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
1326
		}
1327
	}
1328
1329
	// --------------------------------------------------------------------
1330
1331
	/**
1332
	 * CI Object to Array translator
1333
	 *
1334
	 * Takes an object as input and converts the class variables to
1335
	 * an associative array with key/value pairs.
1336
	 *
1337
	 * @param	object	$object	Object data to translate
1338
	 * @return	array
1339
	 */
1340
	protected function _ci_object_to_array($object)
1341
	{
1342
		return is_object($object) ? get_object_vars($object) : $object;
1343
	}
1344
1345
	// --------------------------------------------------------------------
1346
1347
	/**
1348
	 * CI Component getter
1349
	 *
1350
	 * Get a reference to a specific library or model.
1351
	 *
1352
	 * @param 	string	$component	Component name
1353
	 * @return	bool
1354
	 */
1355
	protected function &_ci_get_component($component)
1356
	{
1357
		$CI =& get_instance();
1358
		return $CI->$component;
1359
	}
1360
1361
	// --------------------------------------------------------------------
1362
1363
	/**
1364
	 * Prep filename
1365
	 *
1366
	 * This function prepares filenames of various items to
1367
	 * make their loading more reliable.
1368
	 *
1369
	 * @param	string|string[]	$filename	Filename(s)
1370
	 * @param 	string		$extension	Filename extension
1371
	 * @return	array
1372
	 */
1373
	protected function _ci_prep_filename($filename, $extension)
1374
	{
1375
		if ( ! is_array($filename))
1376
		{
1377
			return array(strtolower(str_replace(array($extension, '.php'), '', $filename).$extension));
1378
		}
1379
		else
1380
		{
1381
			foreach ($filename as $key => $val)
1382
			{
1383
				$filename[$key] = strtolower(str_replace(array($extension, '.php'), '', $val).$extension);
1384
			}
1385
1386
			return $filename;
1387
		}
1388
	}
1389
1390
}
1391