/// <summary> /// Evaluates this chain as if it had the <see cref="PHP.Core.AST.AccessType.ReadRef"/> access type. /// </summary> /// <param name="context">Current script context.</param> /// <returns>The result of chain evaluation.</returns> public PhpReference GetReference(ScriptContext context) { PhpReference reference; RuntimeChainElement element = Chain; if (element == null) { // if we are just wrapping the variable with a PhpReference, make a copy reference = Variable as PhpReference; if (reference == null) { reference = new PhpReference(PhpVariable.Copy(Variable, CopyReason.Unknown)); } return(reference); } // make sure that we have a PhpReference reference = PhpVariable.MakeReference(Variable); if (element == lastElement) { // GetPropertyRef/GetItemRef return(element.GetRef(ref reference.value, context, Caller)); } // EnsureVariableIsObject/EnsureVariableIsArray object var = element.EnsureVariable(ref reference.value, context, Caller); if (var == null) { return(new PhpReference()); } while (element.Next != null) { // Ensure{Field,Item}Is{Object,Array} var = element.Ensure(var, context, Caller); if (var == null) { return(new PhpReference()); } element = element.Next; } // GetObjectPropertyRef/GetArrayItemRef return(element.GetEnsuredRef(var, context, Caller)); }
public PhpReference PeekReferenceUnchecked(int i) { object item = Items[Top - i]; PhpReference result; PhpRuntimeChain php_chain; // the caller may not pushed a reference although the formal argument is a reference: // it doesn't matter if called by callback: if ((result = item as PhpReference) == null) { // caller may have pushed a runtime chain => evaluate it: if ((php_chain = item as PhpRuntimeChain) != null) { // call state has to be stored since chain can call arbitrary user code: CallState call_state = SaveCallState(); result = php_chain.GetReference(Context); RestoreCallState(call_state); } else { // the reason of copy is not exactly known (it may be returning by copy as well as passing by copy): result = new PhpReference(PhpVariable.Copy(item, CopyReason.Unknown)); // Reports an error in the case that we are not called by callback. // Although, this error is fatal one can switch throwing exceptions off. // If this is the case the afterwards behavior will be the same as if callback was called. if (!Callback) { // warning (can invoke user code => we have to save and restore callstate): CallState call_state = SaveCallState(); PhpException.ArgumentNotPassedByRef(i, CalleeName); RestoreCallState(call_state); } } } return(result); }
/// <summary> /// Retrieves a copy of this instance. /// </summary> /// <returns>The copy.</returns> /// <remarks> /// If this <see cref="PhpSmartReference"/> <see cref="IsAliased"/>, this instance is returned without copying. /// That is because (deep) copying stops on references in PHP. If this instance is not <see cref="IsAliased"/>, /// a new <see cref="PhpSmartReference"/> referencing a copy of the current value is returned. /// </remarks> public override object Copy(CopyReason reason) { return(IsAliased ? this : new PhpSmartReference(PhpVariable.Copy(value, reason))); }