<?php

require_once 'common/IObject.php';
require_once 'common/Object.php';

/**
 * Class to perform basic inspection on Objects.
 * 
 * This class offers an object oriented (OO) interface to php methods.
 * All methods can be called statycally, without instantiate this class.
 * So, usually, you will only instantiate it if you plan to do several method 
 * calls.
 * If you need something more advanced, take a look at Reflection clases.
 * <br />
 * <strong>Note:</strong> getInfo() method isn't recursive, so it wan't be 
 * called on any attribute that's also an <em>Object</em> or an array. If you 
 * need this behavoir, feel free to implement it.
 * 
 * @author  $Author: pruna $
 * @package common
 * @version $Revision: 1.3 $
 * @created 13-Apr-2005
 * @modified $Date: 2005/12/06 02:56:45 $
 */
class ObjectInspector extends Object {
    
    /**
     * Internal holder for object to inspect.
     * It's used if null is passed as parameter.
     *
     * @var      object
     * @access   private
     */
    private $object = null;
    
    /**
     * Constructor. If you pass here an object, it will be used when no 
     * parameter is passed to a method.
     *
     * @param     object     $object   Object to inspect
     * @access    public
     */
    public function __construct($object = null) {
        $this->object = $object;
    }
    
    /**
     * Returns attributes for object.
     *
     * @param     object     $object   Object to inspect
     * @access    public
     * @return    array
     */
    public function getAttributes($object = null) {
        return get_class_vars(ObjectInspector::getClass($object));
    }
    
    /**
     * Returns object's class name.
     * 
     * @param     object     $object   Object to inspect
     * @access    public
     * @return    string
     */
    public function getClass($object = null) {
        return get_class(is_null($object) ? $this->object : $object);
    }
    
    /**
     * Returns class hierarchy (all parents), from closest to last.
     *
     * @param     object     $object   Object to inspect
     * @access    public
     * @return    array
     */
    public function getHierarchy($object = null) {
        return class_parents(is_null($object) ? $this->object : $object);
    }
    
    /**
     * Returns string info for object.
     *
     * @param     object     $object   Object to inspect
     * @access    public
     * @return    string
     */
    public function getInfo($object = null) {
        $sp = "\t";
        $attribs = '';
        $oI = new ObjectInspector(is_null($object) ? $this->object : $object);
        foreach ($oI->getAttributes() as $k => $v) {
            $attribs .= $sp . $sp . $k . " [" . gettype($v) . "] : " 
                . $v . PHP_EOL;
        }
        $methods = '';
        foreach ($oI->getMethods() as $v) {
            $methods .= $sp . $sp . $v . PHP_EOL;
        }
        $parents = '';
        foreach ($oI->getHierarchy() as $v) {
            $parents .= $sp . $sp . $v . PHP_EOL;
        }
        $interfaces = '';
        foreach ($oI->getInterfaces() as $v) {
            $interfaces .= $sp . $sp . $v . PHP_EOL;
        }
        return 'Class: ' . $oI->getClass() . PHP_EOL . 
            ($parents?$sp . "Extends: " . PHP_EOL . $parents:'') .
            ($interfaces?$sp . "Implements: " . PHP_EOL . $interfaces:'') . 
            ($attribs?$sp . "Attributes: " . PHP_EOL . $attribs:'') .
            ($methods?$sp . "Methods: " . PHP_EOL . $methods:'');
    }
    
    /**
     * Returns implemented interfaces.
     *
     * @param     object     $object   Object to inspect
     * @access    public
     * @return    array
     */
    public function getInterfaces($object = null) {
        return class_implements(is_null($object) ? $this->object : $object);
    }
    
    /**
     * Returns methods for object.
     *
     * @param     object     $object   Object to inspect
     * @access    public
     * @return    array
     */
    public function getMethods($object = null) {
        return get_class_methods(is_null($object) ? $this->object : $object);
    }
    
    /**
     * Returns parent class.
     *
     * @param     object     $object   Object to inspect
     * @access    public
     * @return    string
     */
    public function getParent($object = null) {
        return get_parent_class(is_null($object) ? $this->object : $object);
    }
    
    /**
     * Checks if an object has a method.<br />
     * Optionally, you can pass only a method name as first parameter, and it 
     * will use internal object to check.
     * 
     * @param     object   $object      Object to inspect
     * @param     string   $methodName  The method name to check on $object.
     * @access    public
     * @return    boolean
     */
    public function hasMethod($object, $methodName = null) {
        return ((is_object($object) && is_string($methodName) 
        && method_exists($object, $methodName))
        ||
        (is_null($methodName) &&
        (is_object($this->object) && is_string($object) 
        && method_exists($this->object, $object))
        ));
    }
    
    /**
     * Checks if an object is of this class or interface.
     * 
     * You can use it with an object and a class. The class can be an 
     * object, or the class name. It can also be used for interfaces and any
     * upper class.<br />
     * Optionally, you can pass only a class as first parameter, and it will 
     * use internal object to check.
     * 
     * @param     object     $object   Object to inspect
     * @param     mixed      $class    Object or class name to check on $object
     * @access    public
     * @return    boolean
     */
    public function isA($object, $class = null) {
        return ((is_object($object) && 
            (is_object($class) || (is_string($class) 
            && (class_exists($class) || interface_exists($class)))) 
            && ($object instanceof $class))
            ||
            (is_null($class) && 
            (is_object($object) || (is_string($object) 
            && (class_exists($object) || interface_exists($object)))) 
            && ($this->object instanceof $object)
            ));
    }
    
    /**
     * Sets object to be inspected.
     *
     * @param   object     $object   Object to inspect
     * @access  public
     */
    public function setObject($object) {
        $this->object = $object;
    }
    
}

?>
