Location: PHPKode > projects > SolarPHP > solar-system-1.1.1/solar/source/solar/Solar/Class.php
<?php
/**
 * 
 * Static support methods for class information.
 * 
 * @category Solar
 * 
 * @package Solar
 * 
 * @author Paul M. Jones <hide@address.com>
 * 
 * @license http://opensource.org/licenses/bsd-license.php BSD
 * 
 * @version $Id: Class.php 4370 2010-02-11 15:41:19Z pmjones $
 * 
 */
class Solar_Class
{
    /**
     * 
     * Parent hierarchy for all classes.
     * 
     * We keep track of this so configs, locale strings, etc. can be
     * inherited properly from parent classes, and so we don't need to
     * recalculate it on each request.
     * 
     * @var array
     * 
     */
    protected static $_parents = array();
    
    /**
     * 
     * Loads a class or interface file from the include_path.
     * 
     * Thanks to Robert Gonzalez  for the report leading to this method.
     * 
     * @param string $name A Solar (or other) class or interface name.
     * 
     * @return void
     * 
     * @todo Add localization for errors
     * 
     */
    public static function autoload($name)
    {
        // did we ask for a non-blank name?
        if (trim($name) == '') {
            throw Solar::exception(
                'Solar_Class',
                'ERR_AUTOLOAD_EMPTY',
                'No class or interface named for loading.',
                array('name' => $name)
            );
        }
        
        // pre-empt further searching for the named class or interface.
        // do not use autoload, because this method is registered with
        // spl_autoload already.
        $exists = class_exists($name, false)
               || interface_exists($name, false);
        
        if ($exists) {
            return;
        }
        
        // convert the class name to a file path
        $file = Solar_Class::nameToFile($name);
        
        // include the file and check for failure. we use Solar_File::load()
        // instead of require() so we can see the exception backtrace.
        Solar_File::load($file);
        
        // if the class or interface was not in the file, we have a problem.
        // do not use autoload, because this method is registered with
        // spl_autoload already.
        $exists = class_exists($name, false)
               || interface_exists($name, false);
        
        if (! $exists) {
            throw Solar::exception(
                'Solar_Class',
                'ERR_AUTOLOAD_FAILED',
                'Class or interface does not exist in loaded file',
                array('name' => $name, 'file' => $file)
            );
        }
    }
    
    /**
     * 
     * Converts a namespace-and-classname to a file path.
     * 
     * Implements PSR-0 as defined by the PHP Project Interoperability Group.
     * 
     * <http://groups.google.com/group/php-standards/web/final-proposal>
     * 
     * @param string $spec The namespace-and-classname.
     * 
     * @return string The converted file path.
     * 
     */
    public static function nameToFile($spec)
    {
        // using namespaces? (look for last namespace separator)
        $pos = strrpos($spec, '\\');
        if ($pos === false) {
            // no namespace, class portion only
            $namespace = '';
            $class     = $spec;
        } else {
            // pre-convert namespace portion to file path
            $namespace = substr($spec, 0, $pos);
            $namespace = str_replace('\\', DIRECTORY_SEPARATOR, $namespace)
                       . DIRECTORY_SEPARATOR;
            
            // class portion
            $class = substr($spec, $pos + 1);
        }
        
        // convert class underscores, and done
        return $namespace
             . str_replace('_',  DIRECTORY_SEPARATOR, $class)
             . '.php';
    }
    
    /**
     * 
     * Returns an array of the parent classes for a given class.
     * 
     * @param string|object $spec The class or object to find parents
     * for.
     * 
     * @param bool $include_class If true, the class name is element 0,
     * the parent is element 1, the grandparent is element 2, etc.
     * 
     * @return array
     * 
     */
    public static function parents($spec, $include_class = false)
    {
        if (is_object($spec)) {
            $class = get_class($spec);
        } else {
            $class = $spec;
        }
        
        // do we need to load the parent stack?
        if (empty(Solar_Class::$_parents[$class])) {
            // use SPL class_parents(), which uses autoload by default.  use
            // only the array values, not the keys, since that messes up BC.
            $parents = array_values(class_parents($class));
            Solar_Class::$_parents[$class] = array_reverse($parents);
        }
        
        // get the parent stack
        $stack = Solar_Class::$_parents[$class];
        
        // add the class itself?
        if ($include_class) {
            $stack[] = $class;
        }
        
        // done
        return $stack;
    }
    
    /**
     * 
     * Returns the directory for a specific class, plus an optional
     * subdirectory path.
     * 
     * @param string|object $spec The class or object to find parents
     * for.
     * 
     * @param string $sub Append this subdirectory.
     * 
     * @return string The class directory, with optional subdirectory.
     * 
     */
    public static function dir($spec, $sub = null)
    {
        if (is_object($spec)) {
            $class = get_class($spec);
        } else {
            $class = $spec;
        }
        
        // convert the class to a base directory to stem from
        $base = str_replace('_', DIRECTORY_SEPARATOR, $class);
        
        // does the directory exist?
        $dir = Solar_Dir::exists($base);
        if (! $dir) {
            throw Solar::exception(
                'Solar_Class',
                'ERR_NO_DIR_FOR_CLASS',
                'Directory does not exist',
                array('class' => $class, 'base' => $base)
            );
        } else {
            return Solar_Dir::fix($dir . DIRECTORY_SEPARATOR. $sub);
        }
    }
    
    /**
     * 
     * Returns the path to a file under a specific class.
     * 
     * @param string|object $spec The class or object to use as the base path.
     * 
     * @param string $file Append this file path.
     * 
     * @return string The path to the file under the class.
     * 
     */
    public static function file($spec, $file)
    {
        $dir = Solar_Class::dir($spec);
        return Solar_File::exists($dir . $file);
    }
    
    /**
     * 
     * Find the vendor name of a given class or object; this is effectively
     * the part of the class name that comes before the first underscore.
     * 
     * @param mixed $spec An object, or a class name.
     * 
     * @return string The vendor name of the class or object.
     * 
     */
    public static function vendor($spec)
    {
        if (is_object($spec)) {
            $class = get_class($spec);
        } else {
            $class = $spec;
        }
        
        // find the first underscore
        $pos = strpos($class, '_');
        if ($pos !== false) {
            // return the part up to the first underscore
            return substr($class, 0, $pos);
        } else {
            // no underscores, must be an arch-class
            return $class;
        }
    }
    
    /**
     * 
     * Find the vendors of a given class or object and its parents.
     * 
     * @param mixed $spec An object, or a class name.
     * 
     * @return array The vendor names of the class or object hierarchy.
     * 
     */
    public static function vendors($spec)
    {
        // vendor listing
        $stack = array();
        
        // get the list of parents
        $parents = Solar_Class::parents($spec, true);
        
        // look through vendor names
        $old = null;
        foreach ($parents as $class) {
            $new = Solar_Class::vendor($class);
            if ($new != $old) {
                // not the same, add the current vendor name and suffix
                $stack[] = $new;
            }
            // retain old vendor for next loop
            $old = $new;
        }
        
        return $stack;
    }
}
Return current item: SolarPHP