public static bool IsA(DTypeDesc caller, object obj, string className) { if (obj == null || !(obj is DObject)) { return(false); } DObject dobj = (DObject)obj; DTypeDesc type = ScriptContext.CurrentContext.ResolveType(className, null, caller, null, ResolveTypeFlags.None); // do not call autoload [workitem:26664] if (type == null) { return(false); } return(type.IsAssignableFrom(dobj.TypeDesc)); }
/// <summary> /// Attemps to find a method desc according to a given class name and method name. Used when /// a non-virtual dispatch is about to be performed and when a <c>array(class, method)</c> /// callback is being bound. /// </summary> /// <param name="requestedType">The type whose method should be returned.</param> /// <param name="methodName">The method name.</param> /// <param name="self">Current <c>$this</c>. Will be set to an instance, on which the resulting /// CLR method should be invoked (<B>null</B> if the CLR method is static).</param> /// <param name="caller"><see cref="Type"/> of the object that request the lookup.</param> /// <param name="context">Current <see cref="ScriptContext"/>.</param> /// <param name="quiet">If <B>true</B>, no exceptions will be thrown if an error occurs.</param> /// <param name="removeFrame">If <B>true</B>, <see cref="PhpStack.RemoveFrame"/> will be called /// before throwing an exception.</param> /// <param name="isCallerMethod">Will be set to true, if required method was not found but __callStatic was.</param> /// <returns>The <see cref="DRoutineDesc"/> or <B>null</B> on error.</returns> internal static DRoutineDesc GetStaticMethodDesc(DTypeDesc requestedType, string methodName, ref DObject self, DTypeDesc caller, ScriptContext context, bool quiet, bool removeFrame, out bool isCallerMethod) { Debug.Assert(requestedType != null); isCallerMethod = false; DRoutineDesc method; GetMemberResult result = requestedType.GetMethod(new Name(methodName), caller, out method); if (result == GetMemberResult.NotFound) { // if not found, perform __callStatic or __call 'magic' method lookup Name callMethod = (self != null && requestedType.IsAssignableFrom(self.TypeDesc)) ? Name.SpecialMethodNames.Call : Name.SpecialMethodNames.CallStatic; if ((result = requestedType.GetMethod(callMethod, caller, out method)) != GetMemberResult.NotFound) { isCallerMethod = true; } else { // there is no such method in the class if (removeFrame) context.Stack.RemoveFrame(); if (!quiet) PhpException.UndefinedMethodCalled(requestedType.MakeFullName(), methodName); return null; } } if (result == GetMemberResult.BadVisibility) { if (removeFrame) context.Stack.RemoveFrame(); if (!quiet) { PhpException.MethodNotAccessible( method.DeclaringType.MakeFullName(), method.MakeFullName(), (caller == null ? String.Empty : caller.MakeFullName()), method.IsProtected); } return null; } // check whether the method is abstract if (method.IsAbstract) { if (removeFrame) context.Stack.RemoveFrame(); if (!quiet) PhpException.AbstractMethodCalled(method.DeclaringType.MakeFullName(), method.MakeFullName()); return null; } if (method.IsStatic) { self = null; } else { // check whether self is of acceptable type if (self != null && !method.DeclaringType.RealType.IsInstanceOfType(self.RealObject)) self = null; /* // PHP allows for static invocations of instance method if (self == null && (requestedType.IsAbstract || !(requestedType is PhpTypeDesc)) && (method.DeclaringType.IsAbstract || !(method.DeclaringType is PhpTypeDesc))) { // calling instance methods declared in abstract classes statically through abstract classes // is unsupported - passing null as 'this' to such instance method could result in // NullReferenceException even if the method does not touch $this if (removeFrame) context.Stack.RemoveFrame(); if (!quiet) { PhpException.Throw(PhpError.Error, CoreResources.GetString("nonstatic_method_called_statically", method.DeclaringType.MakeFullName(), method.MakeFullName())); } return null; } if (self == null) { if (!quiet && !context.Config.Variables.ZendEngineV1Compatible) { PhpException.Throw(PhpError.Strict, CoreResources.GetString("nonstatic_method_called_statically", method.DeclaringType.MakeFullName(), method.MakeFullName())); } // create a dummy instance to be passed as 'this' to the instance method DTypeDesc dummy_type = (!requestedType.IsAbstract && requestedType is PhpTypeDesc) ? requestedType : method.DeclaringType; self = PhpFunctionUtils.InvokeConstructor( dummy_type, //Emit.Types.ScriptContext_Bool, context, false); }*/ // // The code above was commented and replaced with following. // // We can call instance method, and pass null as 'this', and expect // it can fail with NullReferenceException (even if the method does not touch $this). // // Note this solution has no side effect as above - invoking constructor of dummy instance. // // !! self can be null !! if (self == null) { if (!quiet /*&& !context.Config.Variables.ZendEngineV1Compatible*/) { PhpException.Throw(PhpError.Strict, CoreResources.GetString("nonstatic_method_called_statically", method.DeclaringType.MakeFullName(), method.MakeFullName())); } } } return method; }