0001: /*
0002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
0003: *
0004: * This file is part of Resin(R) Open Source
0005: *
0006: * Each copy or derived work must preserve the copyright notice and this
0007: * notice unmodified.
0008: *
0009: * Resin Open Source is free software; you can redistribute it and/or modify
0010: * it under the terms of the GNU General Public License as published by
0011: * the Free Software Foundation; either version 2 of the License, or
0012: * (at your option) any later version.
0013: *
0014: * Resin Open Source is distributed in the hope that it will be useful,
0015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
0017: * of NON-INFRINGEMENT. See the GNU General Public License for more
0018: * details.
0019: *
0020: * You should have received a copy of the GNU General Public License
0021: * along with Resin Open Source; if not, write to the
0022: *
0023: * Free Software Foundation, Inc.
0024: * 59 Temple Place, Suite 330
0025: * Boston, MA 02111-1307 USA
0026: *
0027: * @author Scott Ferguson
0028: */
0029:
0030: package com.caucho.quercus.env;
0031:
0032: import com.caucho.quercus.Location;
0033: import com.caucho.quercus.expr.Expr;
0034: import com.caucho.quercus.expr.StringLiteralExpr;
0035: import com.caucho.quercus.program.AbstractFunction;
0036: import com.caucho.vfs.WriteStream;
0037:
0038: import java.io.IOException;
0039: import java.io.ObjectInputStream;
0040: import java.io.ObjectOutputStream;
0041: import java.io.Serializable;
0042: import java.util.AbstractSet;
0043: import java.util.IdentityHashMap;
0044: import java.util.Iterator;
0045: import java.util.Map;
0046: import java.util.Set;
0047: import java.util.TreeSet;
0048:
0049: /**
0050: * Represents a PHP object value.
0051: */
0052: public class ObjectExtValue extends ObjectValue implements Serializable {
0053: private static final StringValue TO_STRING = new StringBuilderValue(
0054: "__toString");
0055:
0056: private static final int DEFAULT_SIZE = 16;
0057:
0058: private MethodMap<AbstractFunction> _methodMap;
0059:
0060: private Entry[] _entries;
0061: private int _hashMask;
0062:
0063: private int _size;
0064: private boolean _isFieldInit;
0065:
0066: public ObjectExtValue(QuercusClass cl) {
0067: super (cl);
0068:
0069: _methodMap = cl.getMethodMap();
0070:
0071: _entries = new Entry[DEFAULT_SIZE];
0072: _hashMask = _entries.length - 1;
0073: }
0074:
0075: private void init() {
0076: _entries = new Entry[DEFAULT_SIZE];
0077: _hashMask = _entries.length - 1;
0078: }
0079:
0080: @Override
0081: protected void setQuercusClass(QuercusClass cl) {
0082: super .setQuercusClass(cl);
0083:
0084: _methodMap = cl.getMethodMap();
0085: }
0086:
0087: /**
0088: * Returns the number of entries.
0089: */
0090: @Override
0091: public int getSize() {
0092: return _size;
0093: }
0094:
0095: /**
0096: * Gets a field value.
0097: */
0098: @Override
0099: public final Value getField(Env env, StringValue name) {
0100: int hash = name.hashCode() & _hashMask;
0101:
0102: for (Entry entry = _entries[hash]; entry != null; entry = entry._next) {
0103: if (name.equals(entry._key))
0104: return entry._value.toValue();
0105: }
0106:
0107: Value value = getFieldExt(env, name);
0108:
0109: if (value != null)
0110: return value;
0111: else
0112: return _quercusClass.getField(env, this , name);
0113: }
0114:
0115: /**
0116: * Gets a field value.
0117: */
0118: @Override
0119: public Value getThisField(Env env, StringValue name) {
0120: int hash = name.hashCode() & _hashMask;
0121:
0122: for (Entry entry = _entries[hash]; entry != null; entry = entry._next) {
0123: if (name.equals(entry._key))
0124: return entry._value.toValue();
0125: }
0126:
0127: Value value = getFieldExt(env, name);
0128:
0129: if (value != null)
0130: return value;
0131: else
0132: return UnsetValue.UNSET;
0133: }
0134:
0135: /**
0136: * Returns fields not specified by the value.
0137: */
0138: protected Value getFieldExt(Env env, StringValue name) {
0139: return null;
0140: }
0141:
0142: /**
0143: * Returns the array ref.
0144: */
0145: @Override
0146: public Var getFieldRef(Env env, StringValue name) {
0147: Entry entry = createEntry(name);
0148:
0149: Value value = entry._value;
0150:
0151: if (value instanceof Var)
0152: return (Var) value;
0153:
0154: Var var = new Var(value);
0155:
0156: entry.setValue(var);
0157:
0158: return var;
0159: }
0160:
0161: /**
0162: * Returns the array ref.
0163: */
0164: @Override
0165: public Var getThisFieldRef(Env env, StringValue name) {
0166: Entry entry = createEntry(name);
0167:
0168: Value value = entry._value;
0169:
0170: if (value instanceof Var)
0171: return (Var) value;
0172:
0173: Var var = new Var(value);
0174:
0175: entry.setValue(var);
0176:
0177: return var;
0178: }
0179:
0180: /**
0181: * Returns the value as an argument which may be a reference.
0182: */
0183: @Override
0184: public Value getFieldArg(Env env, StringValue name) {
0185: Entry entry = getEntry(name);
0186:
0187: if (entry != null)
0188: return entry.toArg();
0189: else
0190: return new ArgGetFieldValue(env, this , name);
0191: }
0192:
0193: /**
0194: * Returns the value as an argument which may be a reference.
0195: */
0196: @Override
0197: public Value getThisFieldArg(Env env, StringValue name) {
0198: Entry entry = getEntry(name);
0199:
0200: if (entry != null)
0201: return entry.toArg();
0202: else
0203: return new ArgGetFieldValue(env, this , name);
0204: }
0205:
0206: /**
0207: * Returns the value as an argument which may be a reference.
0208: */
0209: @Override
0210: public Value getFieldArgRef(Env env, StringValue name) {
0211: Entry entry = getEntry(name);
0212:
0213: if (entry != null)
0214: return entry.toArg();
0215: else
0216: return new ArgGetFieldValue(env, this , name);
0217: }
0218:
0219: /**
0220: * Returns the value as an argument which may be a reference.
0221: */
0222: @Override
0223: public Value getThisFieldArgRef(Env env, StringValue name) {
0224: Entry entry = getEntry(name);
0225:
0226: if (entry != null)
0227: return entry.toArg();
0228: else
0229: return new ArgGetFieldValue(env, this , name);
0230: }
0231:
0232: /**
0233: * Adds a new value.
0234: */
0235: @Override
0236: public Value putField(Env env, StringValue name, Value value) {
0237: Entry entry = getEntry(name);
0238:
0239: if (entry == null) {
0240: Value oldValue = putFieldExt(env, name, value);
0241:
0242: if (oldValue != null)
0243: return oldValue;
0244:
0245: if (!_isFieldInit) {
0246: AbstractFunction fieldSet = _quercusClass.getFieldSet();
0247:
0248: if (fieldSet != null) {
0249: _isFieldInit = true;
0250: Value retVal = fieldSet.callMethod(env, this , name,
0251: value);
0252: _isFieldInit = false;
0253:
0254: return retVal;
0255: }
0256: }
0257: }
0258:
0259: entry = createEntry(name);
0260:
0261: Value oldValue = entry._value;
0262:
0263: if (value instanceof Var) {
0264: Var var = (Var) value;
0265:
0266: // for function return optimization
0267: var.setReference();
0268:
0269: entry._value = var;
0270: } else if (oldValue instanceof Var) {
0271: oldValue.set(value);
0272: } else {
0273: entry._value = value;
0274: }
0275:
0276: return value;
0277: }
0278:
0279: /**
0280: * Sets/adds field to this object.
0281: */
0282: @Override
0283: public Value putThisField(Env env, StringValue name, Value value) {
0284: Entry entry = getEntry(name);
0285:
0286: if (entry == null) {
0287: Value oldValue = putFieldExt(env, name, value);
0288:
0289: if (oldValue != null)
0290: return oldValue;
0291:
0292: if (!_isFieldInit) {
0293: AbstractFunction fieldSet = _quercusClass.getFieldSet();
0294:
0295: if (fieldSet != null) {
0296: //php/09k7
0297: _isFieldInit = true;
0298:
0299: Value retVal = fieldSet.callMethod(env, this , name,
0300: value);
0301:
0302: _isFieldInit = false;
0303: return retVal;
0304: }
0305: }
0306: }
0307:
0308: entry = createEntry(name);
0309:
0310: Value oldValue = entry._value;
0311:
0312: if (value instanceof Var) {
0313: Var var = (Var) value;
0314:
0315: // for function return optimization
0316: var.setReference();
0317:
0318: entry._value = var;
0319: } else if (oldValue instanceof Var) {
0320: oldValue.set(value);
0321: } else {
0322: entry._value = value;
0323: }
0324:
0325: return value;
0326: }
0327:
0328: protected Value putFieldExt(Env env, StringValue name, Value value) {
0329: return null;
0330: }
0331:
0332: /**
0333: * Adds a new value to the object.
0334: */
0335: @Override
0336: public void initField(StringValue key, Value value) {
0337: Entry entry = createEntry(key);
0338:
0339: entry._value = value;
0340: }
0341:
0342: /**
0343: * Removes a value.
0344: */
0345: @Override
0346: public void unsetField(StringValue name) {
0347: int hash = name.hashCode() & _hashMask;
0348:
0349: for (Entry entry = _entries[hash]; entry != null; entry = entry._next) {
0350: if (name.equals(entry.getKey())) {
0351: Entry prev = entry._prev;
0352: Entry next = entry._next;
0353:
0354: if (prev != null)
0355: prev._next = next;
0356: else
0357: _entries[hash] = next;
0358:
0359: if (next != null)
0360: next._prev = prev;
0361:
0362: _size--;
0363:
0364: return;
0365: }
0366: }
0367: }
0368:
0369: /**
0370: * Gets a new value.
0371: */
0372: private Entry getEntry(StringValue name) {
0373: int hash = name.hashCode() & _hashMask;
0374:
0375: for (Entry entry = _entries[hash]; entry != null; entry = entry._next) {
0376: if (name.equals(entry._key))
0377: return entry;
0378: }
0379:
0380: return null;
0381: }
0382:
0383: /**
0384: * Creates the entry for a key.
0385: */
0386: private Entry createEntry(StringValue name) {
0387: int hash = name.hashCode() & _hashMask;
0388:
0389: for (Entry entry = _entries[hash]; entry != null; entry = entry._next) {
0390: if (name.equals(entry._key))
0391: return entry;
0392: }
0393:
0394: _size++;
0395:
0396: Entry newEntry = new Entry(name);
0397: Entry next = _entries[hash];
0398:
0399: if (next != null) {
0400: newEntry._next = next;
0401: next._prev = newEntry;
0402: }
0403:
0404: _entries[hash] = newEntry;
0405:
0406: // XXX: possibly resize
0407:
0408: return newEntry;
0409: }
0410:
0411: //
0412: // array methods
0413: //
0414:
0415: /**
0416: * Returns the array value with the given key.
0417: */
0418: @Override
0419: public Value get(Value key) {
0420: ArrayDelegate delegate = _quercusClass.getArrayDelegate();
0421:
0422: // php/066q vs. php/0906
0423: //return getField(null, key.toString());
0424:
0425: if (delegate != null)
0426: return delegate.get(this , key);
0427: else
0428: return super .get(key);
0429: }
0430:
0431: /**
0432: * Sets the array value with the given key.
0433: */
0434: @Override
0435: public Value put(Value key, Value value) {
0436: // php/0d94
0437: ArrayDelegate delegate = _quercusClass.getArrayDelegate();
0438:
0439: if (delegate != null)
0440: return delegate.put(this , key, value);
0441: else
0442: return super .put(key, value);
0443: }
0444:
0445: /**
0446: * Appends a new array value
0447: */
0448: @Override
0449: public Value put(Value value) {
0450: // php/0d94
0451: ArrayDelegate delegate = _quercusClass.getArrayDelegate();
0452:
0453: if (delegate != null)
0454: return delegate.put(this , value);
0455: else
0456: return super .put(value);
0457: }
0458:
0459: /**
0460: * Unsets the array value
0461: */
0462: @Override
0463: public Value remove(Value key) {
0464: ArrayDelegate delegate = _quercusClass.getArrayDelegate();
0465:
0466: if (delegate != null)
0467: return delegate.unset(this , key);
0468: else
0469: return super .remove(key);
0470: }
0471:
0472: //
0473: // Foreach/Traversable functions
0474: //
0475:
0476: /**
0477: * Returns an iterator for the key => value pairs.
0478: */
0479: @Override
0480: public Iterator<Map.Entry<Value, Value>> getIterator(Env env) {
0481: TraversableDelegate delegate = _quercusClass
0482: .getTraversableDelegate();
0483:
0484: if (delegate != null)
0485: return delegate.getIterator(env, this );
0486:
0487: return new EntryIterator(_entries);
0488: }
0489:
0490: /**
0491: * Returns an iterator for the keys.
0492: */
0493: @Override
0494: public Iterator<Value> getKeyIterator(Env env) {
0495: TraversableDelegate delegate = _quercusClass
0496: .getTraversableDelegate();
0497:
0498: if (delegate != null)
0499: return delegate.getKeyIterator(env, this );
0500:
0501: return new KeyIterator(_entries);
0502: }
0503:
0504: /**
0505: * Returns an iterator for the values.
0506: */
0507: @Override
0508: public Iterator<Value> getValueIterator(Env env) {
0509: TraversableDelegate delegate = _quercusClass
0510: .getTraversableDelegate();
0511:
0512: if (delegate != null)
0513: return delegate.getValueIterator(env, this );
0514:
0515: return new ValueIterator(_entries);
0516: }
0517:
0518: //
0519: // method calls
0520: //
0521:
0522: /**
0523: * Finds the method name.
0524: */
0525: @Override
0526: public AbstractFunction findFunction(String methodName) {
0527: return _quercusClass.findFunction(methodName);
0528: }
0529:
0530: /**
0531: * Evaluates a method.
0532: */
0533: @Override
0534: public Value callMethod(Env env, int hash, char[] name,
0535: int nameLen, Expr[] args) {
0536: AbstractFunction fun = _methodMap.get(hash, name, nameLen);
0537:
0538: if (fun != null)
0539: return fun.callMethod(env, this , args);
0540: else if (_quercusClass.getCall() != null) {
0541: Expr[] newArgs = new Expr[args.length + 1];
0542: newArgs[0] = new StringLiteralExpr(toMethod(name, nameLen));
0543: System.arraycopy(args, 0, newArgs, 1, args.length);
0544:
0545: return _quercusClass.getCall().callMethod(env, this ,
0546: newArgs);
0547: } else
0548: return env.error(L.l("Call to undefined method {0}::{1}",
0549: getName(), toMethod(name, nameLen)));
0550: }
0551:
0552: /**
0553: * Evaluates a method.
0554: */
0555: @Override
0556: public Value callMethod(Env env, int hash, char[] name,
0557: int nameLen, Value[] args) {
0558: AbstractFunction fun = _methodMap.get(hash, name, nameLen);
0559:
0560: if (fun != null)
0561: return fun.callMethod(env, this , args);
0562: else if ((fun = _quercusClass.getCall()) != null) {
0563: return fun.callMethod(env, this , env.createString(name,
0564: nameLen), new ArrayValueImpl(args));
0565: } else
0566: return env.error(L.l("Call to undefined method {0}::{1}()",
0567: getName(), toMethod(name, nameLen)));
0568: }
0569:
0570: /**
0571: * Evaluates a method.
0572: */
0573: @Override
0574: public Value callMethod(Env env, int hash, char[] name, int nameLen) {
0575: AbstractFunction fun = _methodMap.get(hash, name, nameLen);
0576:
0577: if (fun != null)
0578: return fun.callMethod(env, this );
0579: else if ((fun = _quercusClass.getCall()) != null) {
0580: return fun.callMethod(env, this , env.createString(name,
0581: nameLen), new ArrayValueImpl());
0582: } else
0583: return env.error(L.l("Call to undefined method {0}::{1}()",
0584: getName(), toMethod(name, nameLen)));
0585: }
0586:
0587: /**
0588: * Evaluates a method.
0589: */
0590: @Override
0591: public Value callMethod(Env env, int hash, char[] name,
0592: int nameLen, Value a1) {
0593: AbstractFunction fun = _methodMap.get(hash, name, nameLen);
0594:
0595: if (fun != null)
0596: return fun.callMethod(env, this , a1);
0597: else if ((fun = _quercusClass.getCall()) != null) {
0598: return fun.callMethod(env, this , env.createString(name,
0599: nameLen), new ArrayValueImpl().append(a1));
0600: } else
0601: return env.error(L.l("Call to undefined method {0}::{1}()",
0602: getName(), toMethod(name, nameLen)));
0603: }
0604:
0605: /**
0606: * Evaluates a method.
0607: */
0608: @Override
0609: public Value callMethod(Env env, int hash, char[] name,
0610: int nameLen, Value a1, Value a2) {
0611: AbstractFunction fun = _methodMap.get(hash, name, nameLen);
0612:
0613: if (fun != null)
0614: return fun.callMethod(env, this , a1, a2);
0615: else if ((fun = _quercusClass.getCall()) != null) {
0616: return fun.callMethod(env, this , env.createString(name,
0617: nameLen), new ArrayValueImpl().append(a1)
0618: .append(a2));
0619: } else
0620: return env.error(L.l("Call to undefined method {0}::{1}()",
0621: getName(), toMethod(name, nameLen)));
0622: }
0623:
0624: /**
0625: * calls the function.
0626: */
0627: @Override
0628: public Value callMethod(Env env, int hash, char[] name,
0629: int nameLen, Value a1, Value a2, Value a3) {
0630: AbstractFunction fun = _methodMap.get(hash, name, nameLen);
0631:
0632: if (fun != null)
0633: return fun.callMethod(env, this , a1, a2, a3);
0634: else if ((fun = _quercusClass.getCall()) != null) {
0635: return fun.callMethod(env, this , env.createString(name,
0636: nameLen), new ArrayValueImpl().append(a1)
0637: .append(a2).append(a3));
0638: } else
0639: return env.error(L.l("Call to undefined method {0}::{1}()",
0640: getName(), toMethod(name, nameLen)));
0641: }
0642:
0643: /**
0644: * calls the function.
0645: */
0646: @Override
0647: public Value callMethod(Env env, int hash, char[] name,
0648: int nameLen, Value a1, Value a2, Value a3, Value a4) {
0649: AbstractFunction fun = _methodMap.get(hash, name, nameLen);
0650:
0651: if (fun != null)
0652: return fun.callMethod(env, this , a1, a2, a3, a4);
0653: else if ((fun = _quercusClass.getCall()) != null) {
0654: return fun.callMethod(env, this , env.createString(name,
0655: nameLen), new ArrayValueImpl().append(a1)
0656: .append(a2).append(a3).append(a4));
0657: } else
0658: return env.error(L.l("Call to undefined method {0}::{1}()",
0659: getName(), toMethod(name, nameLen)));
0660: }
0661:
0662: /**
0663: * calls the function.
0664: */
0665: @Override
0666: public Value callMethod(Env env, int hash, char[] name,
0667: int nameLen, Value a1, Value a2, Value a3, Value a4,
0668: Value a5) {
0669: AbstractFunction fun = _methodMap.get(hash, name, nameLen);
0670:
0671: if (fun != null)
0672: return fun.callMethod(env, this , a1, a2, a3, a4, a5);
0673: else if ((fun = _quercusClass.getCall()) != null) {
0674: return fun.callMethod(env, this , env.createString(name,
0675: nameLen), new ArrayValueImpl().append(a1)
0676: .append(a2).append(a3).append(a4).append(a5));
0677: } else
0678: return env.error(L.l("Call to undefined method {0}::{1}()",
0679: getName(), toMethod(name, nameLen)));
0680: }
0681:
0682: /**
0683: * Evaluates a method.
0684: */
0685: @Override
0686: public Value callMethodRef(Env env, int hash, char[] name,
0687: int nameLen, Expr[] args) {
0688: return _quercusClass.callMethodRef(env, this , hash, name,
0689: nameLen, args);
0690: }
0691:
0692: /**
0693: * Evaluates a method.
0694: */
0695: @Override
0696: public Value callMethodRef(Env env, int hash, char[] name,
0697: int nameLen, Value[] args) {
0698: AbstractFunction fun = _methodMap.get(hash, name, nameLen);
0699:
0700: if (fun != null)
0701: return fun.callMethodRef(env, this , args);
0702: else if ((fun = _quercusClass.getCall()) != null) {
0703: return fun.callMethodRef(env, this , env.createString(name,
0704: nameLen), new ArrayValueImpl(args));
0705: } else
0706: return env.error(L.l("Call to undefined method {0}::{1}()",
0707: getName(), toMethod(name, nameLen)));
0708: }
0709:
0710: /**
0711: * Evaluates a method.
0712: */
0713: @Override
0714: public Value callMethodRef(Env env, int hash, char[] name,
0715: int nameLen) {
0716: AbstractFunction fun = _methodMap.get(hash, name, nameLen);
0717:
0718: if (fun != null)
0719: return fun.callMethodRef(env, this );
0720: else if ((fun = _quercusClass.getCall()) != null) {
0721: return fun.callMethodRef(env, this , env.createString(name,
0722: nameLen), new ArrayValueImpl());
0723: } else
0724: return env.error(L.l("Call to undefined method {0}::{1}()",
0725: getName(), toMethod(name, nameLen)));
0726: }
0727:
0728: /**
0729: * Evaluates a method.
0730: */
0731: @Override
0732: public Value callMethodRef(Env env, int hash, char[] name,
0733: int nameLen, Value a1) {
0734: AbstractFunction fun = _methodMap.get(hash, name, nameLen);
0735:
0736: if (fun != null)
0737: return fun.callMethodRef(env, this , a1);
0738: else if ((fun = _quercusClass.getCall()) != null) {
0739: return fun.callMethodRef(env, this , env.createString(name,
0740: nameLen), new ArrayValueImpl().append(a1));
0741: } else
0742: return env.error(L.l("Call to undefined method {0}::{1}()",
0743: getName(), toMethod(name, nameLen)));
0744: }
0745:
0746: /**
0747: * Evaluates a method.
0748: */
0749: @Override
0750: public Value callMethodRef(Env env, int hash, char[] name,
0751: int nameLen, Value a1, Value a2) {
0752: AbstractFunction fun = _methodMap.get(hash, name, nameLen);
0753:
0754: if (fun != null)
0755: return fun.callMethodRef(env, this , a1, a2);
0756: else if ((fun = _quercusClass.getCall()) != null) {
0757: return fun.callMethodRef(env, this , env.createString(name,
0758: nameLen), new ArrayValueImpl().append(a1)
0759: .append(a2));
0760: } else
0761: return env.error(L.l("Call to undefined method {0}::{1}()",
0762: getName(), toMethod(name, nameLen)));
0763: }
0764:
0765: /**
0766: * Evaluates a method.
0767: */
0768: @Override
0769: public Value callMethodRef(Env env, int hash, char[] name,
0770: int nameLen, Value a1, Value a2, Value a3) {
0771: AbstractFunction fun = _methodMap.get(hash, name, nameLen);
0772:
0773: if (fun != null)
0774: return fun.callMethodRef(env, this , a1, a2, a3);
0775: else if ((fun = _quercusClass.getCall()) != null) {
0776: return fun.callMethodRef(env, this , env.createString(name,
0777: nameLen), new ArrayValueImpl().append(a1)
0778: .append(a2).append(a3));
0779: } else
0780: return env.error(L.l("Call to undefined method {0}::{1}()",
0781: getName(), toMethod(name, nameLen)));
0782: }
0783:
0784: /**
0785: * Evaluates a method.
0786: */
0787: @Override
0788: public Value callMethodRef(Env env, int hash, char[] name,
0789: int nameLen, Value a1, Value a2, Value a3, Value a4) {
0790: AbstractFunction fun = _methodMap.get(hash, name, nameLen);
0791:
0792: if (fun != null)
0793: return fun.callMethodRef(env, this , a1, a2, a3, a4);
0794: else if ((fun = _quercusClass.getCall()) != null) {
0795: return fun.callMethodRef(env, this , env.createString(name,
0796: nameLen), new ArrayValueImpl().append(a1)
0797: .append(a2).append(a3).append(a4));
0798: } else
0799: return env.error(L.l("Call to undefined method {0}::{1}()",
0800: getName(), toMethod(name, nameLen)));
0801: }
0802:
0803: /**
0804: * Evaluates a method.
0805: */
0806: @Override
0807: public Value callMethodRef(Env env, int hash, char[] name,
0808: int nameLen, Value a1, Value a2, Value a3, Value a4,
0809: Value a5) {
0810: AbstractFunction fun = _methodMap.get(hash, name, nameLen);
0811:
0812: if (fun != null)
0813: return fun.callMethodRef(env, this , a1, a2, a3, a4, a5);
0814: else if ((fun = _quercusClass.getCall()) != null) {
0815: return fun.callMethodRef(env, this , env.createString(name,
0816: nameLen), new ArrayValueImpl().append(a1)
0817: .append(a2).append(a3).append(a4).append(a5));
0818: } else
0819: return env.error(L.l("Call to undefined method {0}::{1}()",
0820: getName(), toMethod(name, nameLen)));
0821: }
0822:
0823: /**
0824: * Evaluates a method.
0825: */
0826: @Override
0827: public Value callClassMethod(Env env, AbstractFunction fun,
0828: Value[] args) {
0829: return fun.callMethod(env, this , args);
0830: }
0831:
0832: /**
0833: * Returns the value for the variable, creating an object if the var
0834: * is unset.
0835: */
0836: @Override
0837: public Value getObject(Env env) {
0838: return this ;
0839: }
0840:
0841: @Override
0842: public Value getObject(Env env, Value index) {
0843: // php/3d92
0844:
0845: env.error(L.l("Can't use object '{0}' as array", getName()));
0846:
0847: return NullValue.NULL;
0848: }
0849:
0850: /**
0851: * Copy for assignment.
0852: */
0853: @Override
0854: public Value copy() {
0855: return this ;
0856: }
0857:
0858: /**
0859: * Copy for serialization
0860: */
0861: @Override
0862: public Value copy(Env env, IdentityHashMap<Value, Value> map) {
0863: Value oldValue = map.get(this );
0864:
0865: if (oldValue != null)
0866: return oldValue;
0867:
0868: // XXX:
0869: // return new ObjectExtValue(env, map, _cl, getArray());
0870:
0871: return this ;
0872: }
0873:
0874: /**
0875: * Copy for serialization
0876: */
0877: @Override
0878: public Value copyTree(Env env) {
0879: // XXX:
0880: // return new ObjectExtValue(env, map, _cl, getArray());
0881:
0882: return this ;
0883: }
0884:
0885: /**
0886: * Clone the object
0887: */
0888: @Override
0889: public Value clone() {
0890: ObjectExtValue newObject = new ObjectExtValue(_quercusClass);
0891:
0892: for (Map.Entry<Value, Value> entry : entrySet()) {
0893: newObject.putThisField(null, (StringValue) entry.getKey(),
0894: entry.getValue());
0895: }
0896:
0897: return newObject;
0898: }
0899:
0900: // XXX: need to check the other copy, e.g. for sessions
0901:
0902: /**
0903: * Serializes the value.
0904: */
0905: @Override
0906: public void serialize(StringBuilder sb) {
0907: sb.append("O:");
0908: sb.append(_quercusClass.getName().length());
0909: sb.append(":\"");
0910: sb.append(_quercusClass.getName());
0911: sb.append("\":");
0912: sb.append(getSize());
0913: sb.append(":{");
0914:
0915: for (Map.Entry<Value, Value> entry : entrySet()) {
0916: Value key = entry.getKey();
0917:
0918: sb.append("s:");
0919: sb.append(key.length());
0920: sb.append(":\"");
0921: sb.append(key);
0922: sb.append("\";");
0923:
0924: entry.getValue().serialize(sb);
0925: }
0926:
0927: sb.append("}");
0928: }
0929:
0930: /**
0931: * Converts to a string.
0932: * @param env
0933: */
0934: @Override
0935: public StringValue toString(Env env) {
0936: AbstractFunction fun = _quercusClass.findFunction("__toString");
0937:
0938: if (fun != null)
0939: return fun.callMethod(env, this , new Expr[0])
0940: .toStringValue();
0941: else
0942: return env.createString(_quercusClass.getName() + "[]");
0943: }
0944:
0945: /**
0946: * Converts to a string.
0947: * @param env
0948: */
0949: @Override
0950: public void print(Env env) {
0951: env.print(toString(env));
0952: }
0953:
0954: /**
0955: * Converts to an array.
0956: */
0957: @Override
0958: public Value toArray() {
0959: ArrayValue array = new ArrayValueImpl();
0960:
0961: for (Map.Entry<Value, Value> entry : entrySet()) {
0962: array.put(entry.getKey(), entry.getValue());
0963: }
0964:
0965: return array;
0966: }
0967:
0968: /**
0969: * Converts to an object.
0970: */
0971: @Override
0972: public Value toObject(Env env) {
0973: return this ;
0974: }
0975:
0976: /**
0977: * Converts to an object.
0978: */
0979: @Override
0980: public Object toJavaObject() {
0981: return this ;
0982: }
0983:
0984: @Override
0985: public Set<? extends Map.Entry<Value, Value>> entrySet() {
0986: return new EntrySet();
0987: }
0988:
0989: /**
0990: * Returns a Set of entries, sorted by key.
0991: */
0992: public Set<? extends Map.Entry<Value, Value>> sortedEntrySet() {
0993: return new TreeSet<Map.Entry<Value, Value>>(entrySet());
0994: }
0995:
0996: //
0997: // debugging
0998: //
0999:
1000: public void varDumpImpl(Env env, WriteStream out, int depth,
1001: IdentityHashMap<Value, String> valueSet) throws IOException {
1002: // XXX: push up to super, and use varDumpObject
1003: out.println("object(" + getName() + ") (" + getSize() + ") {");
1004:
1005: for (Map.Entry<Value, Value> mapEntry : sortedEntrySet()) {
1006: ObjectExtValue.Entry entry = (ObjectExtValue.Entry) mapEntry;
1007:
1008: entry.varDumpImpl(env, out, depth + 1, valueSet);
1009: }
1010:
1011: printDepth(out, 2 * depth);
1012:
1013: out.print("}");
1014: }
1015:
1016: @Override
1017: protected void printRImpl(Env env, WriteStream out, int depth,
1018: IdentityHashMap<Value, String> valueSet) throws IOException {
1019: out.print(getName());
1020: out.print(' ');
1021: out.println("Object");
1022: printDepth(out, 4 * depth);
1023: out.println("(");
1024:
1025: for (Map.Entry<Value, Value> mapEntry : sortedEntrySet()) {
1026: ObjectExtValue.Entry entry = (ObjectExtValue.Entry) mapEntry;
1027:
1028: entry.printRImpl(env, out, depth + 1, valueSet);
1029: }
1030:
1031: printDepth(out, 4 * depth);
1032: out.println(")");
1033: }
1034:
1035: //
1036: // Java Serialization
1037: //
1038:
1039: private void writeObject(ObjectOutputStream out) throws IOException {
1040: out.writeObject(_quercusClass.getName());
1041:
1042: out.writeInt(_size);
1043:
1044: for (Map.Entry<Value, Value> entry : entrySet()) {
1045: out.writeObject(entry.getKey());
1046: out.writeObject(entry.getValue());
1047: }
1048: }
1049:
1050: private void readObject(ObjectInputStream in)
1051: throws ClassNotFoundException, IOException {
1052: Env env = Env.getInstance();
1053: String name = (String) in.readObject();
1054:
1055: QuercusClass cl = env.findClass(name);
1056:
1057: init();
1058:
1059: if (cl != null) {
1060: setQuercusClass(cl);
1061: } else {
1062: cl = env.getQuercus().getStdClass();
1063:
1064: setQuercusClass(cl);
1065:
1066: putThisField(
1067: env,
1068: env
1069: .createString("__Quercus_Class_Definition_Not_Found"),
1070: env.createString(name));
1071: }
1072:
1073: int size = in.readInt();
1074:
1075: for (int i = 0; i < size; i++) {
1076: putThisField(env, (StringValue) in.readObject(), (Value) in
1077: .readObject());
1078: }
1079: }
1080:
1081: private static String toMethod(char[] key, int keyLength) {
1082: return new String(key, 0, keyLength);
1083: }
1084:
1085: @Override
1086: public String toString() {
1087: return "ObjectExtValue@" + System.identityHashCode(this ) + "["
1088: + _quercusClass.getName() + "]";
1089: }
1090:
1091: public class EntrySet extends AbstractSet<Map.Entry<Value, Value>> {
1092: EntrySet() {
1093: }
1094:
1095: @Override
1096: public int size() {
1097: return ObjectExtValue.this .getSize();
1098: }
1099:
1100: @Override
1101: public Iterator<Map.Entry<Value, Value>> iterator() {
1102: return new EntryIterator(ObjectExtValue.this ._entries);
1103: }
1104: }
1105:
1106: public static class EntryIterator implements
1107: Iterator<Map.Entry<Value, Value>> {
1108: private final Entry[] _list;
1109: private int _index;
1110: private Entry _entry;
1111:
1112: EntryIterator(Entry[] list) {
1113: _list = list;
1114: }
1115:
1116: public boolean hasNext() {
1117: if (_entry != null)
1118: return true;
1119:
1120: for (; _index < _list.length && _list[_index] == null; _index++) {
1121: }
1122:
1123: return _index < _list.length;
1124: }
1125:
1126: public Map.Entry<Value, Value> next() {
1127: if (_entry != null) {
1128: Entry entry = _entry;
1129: _entry = entry._next;
1130:
1131: return entry;
1132: }
1133:
1134: for (; _index < _list.length && _list[_index] == null; _index++) {
1135: }
1136:
1137: if (_list.length <= _index)
1138: return null;
1139:
1140: Entry entry = _list[_index++];
1141: _entry = entry._next;
1142:
1143: return entry;
1144: }
1145:
1146: public void remove() {
1147: throw new UnsupportedOperationException();
1148: }
1149: }
1150:
1151: public static class ValueIterator implements Iterator<Value> {
1152: private final Entry[] _list;
1153: private int _index;
1154: private Entry _entry;
1155:
1156: ValueIterator(Entry[] list) {
1157: _list = list;
1158: }
1159:
1160: public boolean hasNext() {
1161: if (_entry != null)
1162: return true;
1163:
1164: for (; _index < _list.length && _list[_index] == null; _index++) {
1165: }
1166:
1167: return _index < _list.length;
1168: }
1169:
1170: public Value next() {
1171: if (_entry != null) {
1172: Entry entry = _entry;
1173: _entry = entry._next;
1174:
1175: return entry._value;
1176: }
1177:
1178: for (; _index < _list.length && _list[_index] == null; _index++) {
1179: }
1180:
1181: if (_list.length <= _index)
1182: return null;
1183:
1184: Entry entry = _list[_index++];
1185: _entry = entry._next;
1186:
1187: return entry._value;
1188: }
1189:
1190: public void remove() {
1191: throw new UnsupportedOperationException();
1192: }
1193: }
1194:
1195: public static class KeyIterator implements Iterator<Value> {
1196: private final Entry[] _list;
1197: private int _index;
1198: private Entry _entry;
1199:
1200: KeyIterator(Entry[] list) {
1201: _list = list;
1202: }
1203:
1204: public boolean hasNext() {
1205: if (_entry != null)
1206: return true;
1207:
1208: for (; _index < _list.length && _list[_index] == null; _index++) {
1209: }
1210:
1211: return _index < _list.length;
1212: }
1213:
1214: public Value next() {
1215: if (_entry != null) {
1216: Entry entry = _entry;
1217: _entry = entry._next;
1218:
1219: return entry._key;
1220: }
1221:
1222: for (; _index < _list.length && _list[_index] == null; _index++) {
1223: }
1224:
1225: if (_list.length <= _index)
1226: return null;
1227:
1228: Entry entry = _list[_index++];
1229: _entry = entry._next;
1230:
1231: return entry._key;
1232: }
1233:
1234: public void remove() {
1235: throw new UnsupportedOperationException();
1236: }
1237: }
1238:
1239: public final static class Entry implements Map.Entry<Value, Value>,
1240: Comparable<Map.Entry<Value, Value>> {
1241: private final StringValue _key;
1242: private Value _value;
1243:
1244: Entry _prev;
1245: Entry _next;
1246:
1247: public Entry(StringValue key) {
1248: _key = key;
1249: _value = NullValue.NULL;
1250: }
1251:
1252: public Entry(StringValue key, Value value) {
1253: _key = key;
1254: _value = value;
1255: }
1256:
1257: public Value getValue() {
1258: return _value.toValue();
1259: }
1260:
1261: public Value getKey() {
1262: return _key;
1263: }
1264:
1265: public Value toValue() {
1266: // The value may be a var
1267: // XXX: need test
1268: return _value.toValue();
1269: }
1270:
1271: /**
1272: * Argument used/declared as a ref.
1273: */
1274: public Var toRefVar() {
1275: Var var = _value.toRefVar();
1276:
1277: _value = var;
1278:
1279: return var;
1280: }
1281:
1282: /**
1283: * Converts to an argument value.
1284: */
1285: public Value toArgValue() {
1286: return _value.toValue();
1287: }
1288:
1289: public Value setValue(Value value) {
1290: Value oldValue = toValue();
1291:
1292: _value = value;
1293:
1294: return oldValue;
1295: }
1296:
1297: /**
1298: * Converts to a variable reference (for function arguments)
1299: */
1300: public Value toRef() {
1301: Value value = _value;
1302:
1303: if (value instanceof Var)
1304: return new RefVar((Var) value);
1305: else {
1306: Var var = new Var(_value);
1307:
1308: _value = var;
1309:
1310: return new RefVar(var);
1311: }
1312: }
1313:
1314: /**
1315: * Converts to a variable reference (for function arguments)
1316: */
1317: public Value toArgRef() {
1318: Value value = _value;
1319:
1320: if (value instanceof Var)
1321: return new RefVar((Var) value);
1322: else {
1323: Var var = new Var(_value);
1324:
1325: _value = var;
1326:
1327: return new RefVar(var);
1328: }
1329: }
1330:
1331: public Value toArg() {
1332: Value value = _value;
1333:
1334: if (value instanceof Var)
1335: return value;
1336: else {
1337: Var var = new Var(_value);
1338:
1339: _value = var;
1340:
1341: return var;
1342: }
1343: }
1344:
1345: public int compareTo(Map.Entry<Value, Value> other) {
1346: if (other == null)
1347: return 1;
1348:
1349: Value this Key = getKey();
1350: Value otherKey = other.getKey();
1351:
1352: if (this Key == null)
1353: return otherKey == null ? 0 : -1;
1354:
1355: if (otherKey == null)
1356: return 1;
1357:
1358: return this Key.cmp(otherKey);
1359: }
1360:
1361: public void varDumpImpl(Env env, WriteStream out, int depth,
1362: IdentityHashMap<Value, String> valueSet)
1363: throws IOException {
1364: printDepth(out, 2 * depth);
1365: out.println("[\"" + getKey() + "\"]=>");
1366:
1367: printDepth(out, 2 * depth);
1368:
1369: _value.varDump(env, out, depth, valueSet);
1370:
1371: out.println();
1372: }
1373:
1374: protected void printRImpl(Env env, WriteStream out, int depth,
1375: IdentityHashMap<Value, String> valueSet)
1376: throws IOException {
1377: printDepth(out, 4 * depth);
1378: out.print("[" + getKey() + "] => ");
1379:
1380: _value.printR(env, out, depth + 1, valueSet);
1381:
1382: out.println();
1383: }
1384:
1385: private void printDepth(WriteStream out, int depth)
1386: throws java.io.IOException {
1387: for (int i = 0; i < depth; i++)
1388: out.print(' ');
1389: }
1390:
1391: @Override
1392: public String toString() {
1393: return "ObjectExtValue.Entry[" + getKey() + "]";
1394: }
1395: }
1396: }
|