예제 #1
0
        /// <summary>
        /// Ensures that a property value is of <see cref="DObject"/> type.
        /// </summary>
        /// <param name="obj">The object whose property is to be checked.</param>
        /// <param name="name">The property name.</param>
        /// <param name="caller"><see cref="Type"/> of the object that request the operation.</param>
        /// <param name="propValue">The property value (might get updated).</param>
        /// <param name="context">The current <see cref="ScriptContext"/>.</param>
        /// <returns>The new property value (dereferenced) or <B>null</B> if evaluation of this compound
        /// statement should not proceed.</returns>
        internal static DObject EnsurePropertyIsObjectInternal(DObject obj, string name, DTypeDesc caller, ref object propValue,
            ScriptContext context)
        {
            DObject result;
            PhpReference reference = propValue as PhpReference;

            object value;
            if (reference != null && !reference.IsSet)
            {
                // this CT property has been unset
                if (obj.TypeDesc.GetMethod(Name.SpecialMethodNames.Set) != null &&
                    obj.TypeDesc.RealType.Namespace != null &&
                    obj.TypeDesc.RealType.Namespace.StartsWith(Namespaces.Library))
                {
                    // create a chain of arguments to be passed to the setter
                    context.BeginSetterChain(obj);
                    context.ExtendSetterChain(new RuntimeChainProperty(name));

                    return ScriptContext.SetterChainSingletonObject;
                }

                // try to invoke __get
                bool getter_exists;
                reference = obj.InvokeGetterRef(name, caller, out getter_exists);
                if (!getter_exists)
                {
                    result = stdClass.CreateDefaultObject(context);
                    propValue = new PhpReference(result);
                    return result;
                }
                else if (reference == null) return null; // error

                value = reference.Value;
            }
            else value = PhpVariable.Dereference(propValue);

            // if property value is a DObject, nothing has to be done
            result = value as DObject;
            if (result != null) return result;

            // if the property is "empty"?
            if (IsEmptyForEnsure(value))
            {
                // create a new stdClass and update the reference
                result = stdClass.CreateDefaultObject(context);
                if (reference != null)
                {
                    reference.Value = result;
                    reference.IsSet = true;
                }
                else propValue = result;
                return result;
            }

            // error - the property is a scalar or a PhpArray or a non-empty string
            PhpException.VariableMisusedAsObject(value, false);
            return null;
        }