public function getAttribute($object, $name, array $args = array(), $type = self::ANY_CALL)
    {
        // array
        if ($type == self::ANY_CALL || $type == self::ARRAY_CALL) {

            $key = is_bool($name) || is_float($name) ? (int) $name : $name;

            if ((is_array($object) && array_key_exists($key, $object)) || ($object instanceof \ArrayAccess && isset($object[$key]))) {
                return $object[$key];
            }

            if ($type == self::ARRAY_CALL) {
                return null;
            }
        }

        // object
        if (!is_object($object)) {
            return null;
        }

        // property
        if ($type == self::ANY_CALL && isset($object->$name)) {
            return $object->$name;
        }

        // method
        $call  = false;
        $name  = (string) $name;
        $item  = strtolower($name);
        $class = get_class($object);

        if (!isset(self::$classes[$class])) {
            self::$classes[$class] = array_change_key_case(array_flip(get_class_methods($object)));
        }

        if (!isset(self::$classes[$class][$item])) {
            if (isset(self::$classes[$class]["get$item"])) {
                $name = "get$name";
            } elseif (isset(self::$classes[$class]["is$item"])) {
                $name = "is$name";
            } elseif (isset(self::$classes[$class]["__call"])) {
                $call = true;
            } else {
                return null;
            }
        }

        try {
            return call_user_func_array(array($object, $name), $args);
        } catch (\BadMethodCallException $e) {
            if (!$call) throw $e;
        }
    }