Chip away at ClassInfo::FindClass() and ObjectData cruft
Esse commit está contido em:
@@ -29,6 +29,7 @@
|
||||
#include <runtime/base/variable_serializer.h>
|
||||
#include <runtime/base/program_functions.h>
|
||||
#include <runtime/eval/runtime/file_repository.h>
|
||||
#include <runtime/ext_hhvm/ext_hhvm.h>
|
||||
|
||||
#include <compiler/builtin_symbols.h>
|
||||
#include <compiler/analysis/class_scope.h>
|
||||
|
||||
@@ -40,6 +40,8 @@ DECLARE_BOOST_TYPES(SimpleFunctionCall);
|
||||
DECLARE_BOOST_TYPES(SwitchStatement);
|
||||
DECLARE_BOOST_TYPES(ForEachStatement);
|
||||
class StaticClassName;
|
||||
class HhbcExtFuncInfo;
|
||||
class HhbcExtClassInfo;
|
||||
|
||||
namespace Compiler {
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -289,7 +289,6 @@ BeginClass(
|
||||
virtual int64_t o_toInt64() const;
|
||||
virtual double o_toDouble() const;
|
||||
virtual Array o_toArray() const;
|
||||
virtual Variant *___lval(Variant v_name);
|
||||
private:
|
||||
xmlXPathContextPtr m_xpath;
|
||||
EOT
|
||||
|
||||
@@ -1031,14 +1031,11 @@ ClassInfo::MethodInfo::~MethodInfo() {
|
||||
|
||||
void ClassInfo::GetArray(const ObjectData *obj,
|
||||
Array &props, GetArrayKind kind) {
|
||||
HPHP::VM::Instance *inst = static_cast<HPHP::VM::Instance*>(
|
||||
const_cast<ObjectData*>(obj));
|
||||
inst->HPHP::VM::Instance::o_getArray(props, !(kind & GetArrayPrivate));
|
||||
obj->o_getArray(props, !(kind & GetArrayPrivate));
|
||||
}
|
||||
|
||||
void ClassInfo::SetArray(ObjectData *obj, CArrRef props) {
|
||||
HPHP::VM::Instance *inst = static_cast<HPHP::VM::Instance*>(obj);
|
||||
inst->HPHP::VM::Instance::o_setArray(props);
|
||||
obj->o_setArray(props);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -50,7 +50,7 @@ UserFile::UserFile(VM::Class *cls, int options /*= 0 */,
|
||||
}
|
||||
|
||||
m_obj = VM::Instance::newInstance(cls);
|
||||
m_obj.o_setPublic("context", context);
|
||||
m_obj.o_set("context", context);
|
||||
Variant ret;
|
||||
g_vmContext->invokeFunc(ret.asTypedValue(), ctor,
|
||||
Array::Create(), m_obj.get());
|
||||
|
||||
@@ -104,17 +104,6 @@ CStrRef ObjectData::o_getParentName() const {
|
||||
return *(const String*)(&m_cls->m_preClass->parentRef());
|
||||
}
|
||||
|
||||
CStrRef ObjectData::GetParentName(CStrRef cls) {
|
||||
const ClassInfo *classInfo = ClassInfo::FindClass(cls);
|
||||
if (classInfo) {
|
||||
CStrRef parentClass = classInfo->getParentClass();
|
||||
if (!parentClass.isNull()) {
|
||||
return parentClass;
|
||||
}
|
||||
}
|
||||
return empty_string;
|
||||
}
|
||||
|
||||
CStrRef ObjectData::o_getClassNameHook() const {
|
||||
throw FatalErrorException("Class didnt provide a name");
|
||||
return empty_string;
|
||||
@@ -197,10 +186,8 @@ void ObjectData::initProperties(int nProp) {
|
||||
if (!o_properties.get()) ((HPHP::VM::Instance*)this)->initDynProps(nProp);
|
||||
}
|
||||
|
||||
void *ObjectData::o_realPropTyped(CStrRef propName, int flags,
|
||||
CStrRef context, DataType *type) const {
|
||||
*type = KindOfUnknown;
|
||||
|
||||
Variant* ObjectData::o_realProp(CStrRef propName, int flags,
|
||||
CStrRef context /* = null_string */) const {
|
||||
/*
|
||||
* Returns a pointer to a place for a property value. This should never
|
||||
* call the magic methods __get or __set. The flags argument describes the
|
||||
@@ -219,19 +206,18 @@ void *ObjectData::o_realPropTyped(CStrRef propName, int flags,
|
||||
accessible, unset)
|
||||
: thiz->getProp(ctx, propName.get(), visible,
|
||||
accessible, unset);
|
||||
if (ret == nullptr) {
|
||||
if (!ret) {
|
||||
// Property is not declared, and not dynamically created yet.
|
||||
if (flags & RealPropCreate) {
|
||||
assert(!(flags & RealPropNoDynamic));
|
||||
if (o_properties.get() == nullptr) {
|
||||
thiz->initDynProps();
|
||||
}
|
||||
o_properties.get()->lvalPtr(propName,
|
||||
*(Variant**)(&ret), false, true);
|
||||
return (Variant*)ret;
|
||||
} else {
|
||||
if (!(flags & RealPropCreate)) {
|
||||
return nullptr;
|
||||
}
|
||||
assert(!(flags & RealPropNoDynamic));
|
||||
if (!o_properties.get()) {
|
||||
thiz->initDynProps();
|
||||
}
|
||||
o_properties.get()->lvalPtr(propName,
|
||||
*(Variant**)(&ret), false, true);
|
||||
return (Variant*)ret;
|
||||
}
|
||||
|
||||
// ret is non-NULL if we reach here
|
||||
@@ -244,31 +230,6 @@ void *ObjectData::o_realPropTyped(CStrRef propName, int flags,
|
||||
}
|
||||
}
|
||||
|
||||
Variant *ObjectData::o_realProp(CStrRef propName, int flags,
|
||||
CStrRef context /* = null_string */) const {
|
||||
DataType type;
|
||||
if (void *p = o_realPropTyped(propName, flags, context, &type)) {
|
||||
if (LIKELY(type == KindOfUnknown)) return (Variant*)p;
|
||||
if (flags & (RealPropCreate|RealPropWrite)) return nullptr;
|
||||
SystemGlobals* globals = get_system_globals();
|
||||
Variant *res = &globals->__realPropProxy;
|
||||
*res = ClassInfo::GetVariant(type, p);
|
||||
return res;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Variant *ObjectData::o_realPropPublic(CStrRef propName, int flags) const {
|
||||
return o_realProp(propName, flags, empty_string);
|
||||
}
|
||||
|
||||
bool ObjectData::o_exists(CStrRef propName,
|
||||
CStrRef context /* = null_string */) const {
|
||||
const Variant *t = o_realProp(propName, RealPropUnchecked, context);
|
||||
return t && t->isInitialized();
|
||||
}
|
||||
|
||||
inline Variant ObjectData::o_getImpl(CStrRef propName, int flags,
|
||||
bool error /* = true */,
|
||||
CStrRef context /* = null_string */) {
|
||||
@@ -287,7 +248,8 @@ inline Variant ObjectData::o_getImpl(CStrRef propName, int flags,
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return o_getError(propName, context);
|
||||
raise_notice("Undefined property: %s::$%s", o_getClassName().data(),
|
||||
propName.data());
|
||||
}
|
||||
|
||||
return uninit_null();
|
||||
@@ -298,33 +260,6 @@ Variant ObjectData::o_get(CStrRef propName, bool error /* = true */,
|
||||
return o_getImpl(propName, 0, error, context);
|
||||
}
|
||||
|
||||
Variant ObjectData::o_getPublic(CStrRef propName, bool error /* = true */) {
|
||||
if (UNLIKELY(!*propName.data())) {
|
||||
throw_invalid_property_name(propName);
|
||||
}
|
||||
|
||||
if (Variant *t = o_realPropPublic(propName, 0)) {
|
||||
if (t->isInitialized())
|
||||
return *t;
|
||||
}
|
||||
|
||||
if (getAttribute(UseGet)) {
|
||||
AttributeClearer a(UseGet, this);
|
||||
return t___get(propName);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return o_getError(propName, null_string);
|
||||
}
|
||||
|
||||
return uninit_null();
|
||||
}
|
||||
|
||||
Variant ObjectData::o_getUnchecked(CStrRef propName,
|
||||
CStrRef context /* = null_string */) {
|
||||
return o_getImpl(propName, RealPropUnchecked, true, context);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline ALWAYS_INLINE Variant ObjectData::o_setImpl(CStrRef propName, T v,
|
||||
bool forInit,
|
||||
@@ -334,7 +269,7 @@ inline ALWAYS_INLINE Variant ObjectData::o_setImpl(CStrRef propName, T v,
|
||||
}
|
||||
|
||||
bool useSet = !forInit && getAttribute(UseSet);
|
||||
int flags = useSet ? RealPropWrite : RealPropCreate | RealPropWrite;
|
||||
int flags = useSet ? 0 : RealPropCreate;
|
||||
if (forInit) flags |= RealPropUnchecked;
|
||||
|
||||
if (Variant *t = o_realProp(propName, flags, context)) {
|
||||
@@ -350,7 +285,6 @@ inline ALWAYS_INLINE Variant ObjectData::o_setImpl(CStrRef propName, T v,
|
||||
return variant(v);
|
||||
}
|
||||
|
||||
o_setError(propName, context);
|
||||
return variant(v);
|
||||
}
|
||||
|
||||
@@ -378,70 +312,64 @@ Variant ObjectData::o_setRef(CStrRef propName, CVarRef v, CStrRef context) {
|
||||
return o_setImpl<RefResult>(propName, ref(v), false, context);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline ALWAYS_INLINE Variant ObjectData::o_setPublicImpl(CStrRef propName,
|
||||
T v,
|
||||
bool forInit) {
|
||||
if (UNLIKELY(!*propName.data())) {
|
||||
throw_invalid_property_name(propName);
|
||||
}
|
||||
|
||||
bool useSet = !forInit && getAttribute(UseSet);
|
||||
int flags = useSet ? RealPropWrite : RealPropCreate | RealPropWrite;
|
||||
if (forInit) flags |= RealPropUnchecked;
|
||||
|
||||
if (Variant *t = o_realPropPublic(propName, flags)) {
|
||||
if (!useSet || t->isInitialized()) {
|
||||
*t = v;
|
||||
return variant(v);
|
||||
}
|
||||
}
|
||||
|
||||
if (useSet) {
|
||||
AttributeClearer a(UseSet, this);
|
||||
t___set(propName, variant(v));
|
||||
return variant(v);
|
||||
}
|
||||
|
||||
o_setError(propName, null_string);
|
||||
return variant(v);
|
||||
}
|
||||
|
||||
Variant ObjectData::o_setPublic(CStrRef propName, CVarRef v) {
|
||||
return o_setPublicImpl<CVarRef>(propName, v, false);
|
||||
}
|
||||
|
||||
Variant ObjectData::o_setPublic(CStrRef propName, RefResult v) {
|
||||
return o_setPublicRef(propName, variant(v));
|
||||
}
|
||||
|
||||
Variant ObjectData::o_setPublicRef(CStrRef propName, CVarRef v) {
|
||||
return o_setPublicImpl<CVarStrongBind>(propName, strongBind(v), false);
|
||||
}
|
||||
|
||||
Variant ObjectData::o_i_setPublicWithRef(CStrRef propName, CVarRef v) {
|
||||
return o_setPublicImpl<CVarWithRefBind>(propName, withRefBind(v), true);
|
||||
}
|
||||
|
||||
HOT_FUNC
|
||||
void ObjectData::o_setArray(CArrRef properties) {
|
||||
auto thiz = static_cast<VM::Instance*>(this);
|
||||
for (ArrayIter iter(properties); iter; ++iter) {
|
||||
String key = iter.first().toString();
|
||||
if (key.empty() || key.charAt(0) != '\0') {
|
||||
// non-private property
|
||||
CVarRef secondRef = iter.secondRef();
|
||||
o_i_setPublicWithRef(key, secondRef);
|
||||
String k = iter.first().toString();
|
||||
VM::Class* ctx = nullptr;
|
||||
// If the key begins with a NUL, it's a private or protected property. Read
|
||||
// the class name from between the two NUL bytes.
|
||||
if (!k.empty() && k.charAt(0) == '\0') {
|
||||
int subLen = k.find('\0', 1) + 1;
|
||||
String cls = k.substr(1, subLen - 2);
|
||||
if (cls == "*") {
|
||||
// Protected.
|
||||
ctx = m_cls;
|
||||
} else {
|
||||
// Private.
|
||||
ctx = VM::Unit::lookupClass(cls.get());
|
||||
if (!ctx) continue;
|
||||
}
|
||||
k = k.substr(subLen);
|
||||
}
|
||||
|
||||
CVarRef secondRef = iter.secondRef();
|
||||
thiz->setProp(ctx, k.get(), (TypedValue*)(&secondRef),
|
||||
secondRef.isReferenced());
|
||||
}
|
||||
}
|
||||
|
||||
void ObjectData::o_getArray(Array &props, bool pubOnly /* = false */) const {
|
||||
const Array& arr = o_properties.asArray();
|
||||
if (!arr.empty()) {
|
||||
for (ArrayIter it(arr); !it.end(); it.next()) {
|
||||
// The declared properties in the resultant array should be a permutation of
|
||||
// propVec. They appear in the following order: go most-to-least-derived in
|
||||
// the inheritance hierarchy, inserting properties in declaration order (with
|
||||
// the wrinkle that overridden properties should appear only once, with the
|
||||
// access level given to it in its most-derived declaration).
|
||||
|
||||
// This is needed to keep track of which elements have been inserted. This is
|
||||
// the smoothest way to get overridden properties right.
|
||||
std::vector<bool> inserted(m_cls->numDeclProperties(), false);
|
||||
|
||||
// Iterate over declared properties and insert {mangled name --> prop} pairs.
|
||||
const VM::Class* cls = m_cls;
|
||||
auto thiz = static_cast<const VM::Instance*>(this);
|
||||
do {
|
||||
thiz->getProps(cls, pubOnly, cls->m_preClass.get(), props, inserted);
|
||||
const std::vector<VM::ClassPtr> &usedTraits = cls->m_usedTraits;
|
||||
for (unsigned t = 0; t < usedTraits.size(); t++) {
|
||||
const VM::ClassPtr& trait = usedTraits[t];
|
||||
thiz->getProps(cls, pubOnly, trait->m_preClass.get(), props, inserted);
|
||||
}
|
||||
cls = cls->m_parent.get();
|
||||
} while (cls);
|
||||
|
||||
// Iterate over dynamic properties and insert {name --> prop} pairs.
|
||||
if (o_properties.get() && !o_properties.get()->empty()) {
|
||||
for (ArrayIter it(o_properties.get()); !it.end(); it.next()) {
|
||||
Variant key = it.first();
|
||||
CVarRef value = it.secondRef();
|
||||
props.lvalAt(key, AccessFlags::Key).setWithRef(value);
|
||||
props.addLval(key, true).setWithRef(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -454,55 +382,6 @@ Object ObjectData::FromArray(ArrayData *properties) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
CVarRef ObjectData::set(CStrRef s, CVarRef v) {
|
||||
o_set(s, v);
|
||||
return v;
|
||||
}
|
||||
|
||||
Variant &ObjectData::o_lval(CStrRef propName, CVarRef tmpForGet,
|
||||
CStrRef context /* = null_string */) {
|
||||
if (UNLIKELY(!*propName.data())) {
|
||||
throw_invalid_property_name(propName);
|
||||
}
|
||||
|
||||
bool useGet = getAttribute(UseGet);
|
||||
int flags = useGet ? RealPropWrite : RealPropCreate | RealPropWrite;
|
||||
if (Variant *t = o_realProp(propName, flags, context)) {
|
||||
if (!useGet || t->isInitialized()) {
|
||||
return *t;
|
||||
}
|
||||
}
|
||||
|
||||
Variant &ret = const_cast<Variant&>(tmpForGet);
|
||||
if (LIKELY(useGet)) {
|
||||
AttributeClearer a(UseGet, this);
|
||||
if (getAttribute(HasLval)) {
|
||||
return *___lval(propName);
|
||||
}
|
||||
|
||||
ret = t___get(propName);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* we only get here if its a protected property
|
||||
under hphpi - and then o_getError fatals
|
||||
with a suitable message
|
||||
*/
|
||||
ret = o_getError(propName, context);
|
||||
return ret;
|
||||
}
|
||||
|
||||
Variant *ObjectData::o_weakLval(CStrRef propName,
|
||||
CStrRef context /* = null_string */) {
|
||||
if (Variant *t = o_realProp(propName, RealPropWrite|RealPropUnchecked,
|
||||
context)) {
|
||||
if (t->isInitialized()) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Array ObjectData::o_toArray() const {
|
||||
Array ret(ArrayData::Create());
|
||||
ClassInfo::GetArray(this, ret, ClassInfo::GetArrayAll);
|
||||
@@ -522,7 +401,7 @@ Array ObjectData::o_toIterArray(CStrRef context,
|
||||
// Get all declared properties first, bottom-to-top in the inheritance
|
||||
// hierarchy, in declaration order.
|
||||
const VM::Class* klass = m_cls;
|
||||
while (klass != nullptr) {
|
||||
while (klass) {
|
||||
const VM::PreClass::Prop* props = klass->m_preClass->properties();
|
||||
const size_t numProps = klass->m_preClass->numProperties();
|
||||
|
||||
@@ -670,47 +549,6 @@ Variant ObjectData::o_invoke_few_args(CStrRef s, strhash_t hash, int count,
|
||||
return o_invoke(s, params, hash);
|
||||
}
|
||||
|
||||
Variant ObjectData::o_invoke_ex(CStrRef clsname, CStrRef s,
|
||||
CArrRef params, bool fatal /* = true */) {
|
||||
// TODO This duplicates some logic from vm_decode_function and
|
||||
// vm_call_user_func, we should refactor this in the near future
|
||||
ObjectData* this_ = this;
|
||||
HPHP::VM::Class* cls = VM::Unit::lookupClass(clsname.get());
|
||||
if (!cls || !getVMClass()->classof(cls)) {
|
||||
o_invoke_failed(clsname.data(), s.data(), fatal);
|
||||
return uninit_null();
|
||||
}
|
||||
StringData* invName = nullptr;
|
||||
// XXX The lookup below doesn't take context into account, so it will lead
|
||||
// to incorrect behavior in some corner cases. o_invoke is gradually being
|
||||
// removed from the HPHP runtime this should be ok for the short term.
|
||||
const HPHP::VM::Func* f = cls->lookupMethod(s.get());
|
||||
if (f && (f->attrs() & HPHP::VM::AttrStatic)) {
|
||||
// If we found a method and its static, null out this_
|
||||
this_ = nullptr;
|
||||
} else if (!f) {
|
||||
if (this_) {
|
||||
// If this_ is non-null AND we could not find a method, try
|
||||
// looking up __call in cls's method table
|
||||
f = cls->lookupMethod(s___call.get());
|
||||
}
|
||||
if (!f) {
|
||||
// Bail if we couldn't find the method or __call
|
||||
o_invoke_failed(clsname.data(), s.data(), fatal);
|
||||
return uninit_null();
|
||||
}
|
||||
// We found __call! Stash the original name into invName.
|
||||
assert(!(f->attrs() & HPHP::VM::AttrStatic));
|
||||
invName = s.get();
|
||||
invName->incRefCount();
|
||||
}
|
||||
assert(f);
|
||||
Variant ret;
|
||||
g_vmContext->invokeFunc((TypedValue*)&ret, f, params, this_, cls,
|
||||
nullptr, invName);
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ObjectData::php_sleep(Variant &ret) {
|
||||
setAttribute(HasSleep);
|
||||
ret = t___sleep();
|
||||
@@ -783,19 +621,24 @@ void ObjectData::serializeImpl(VariableSerializer *serializer) const {
|
||||
if (UNLIKELY(handleSleep)) {
|
||||
assert(!isCollection());
|
||||
if (ret.isArray()) {
|
||||
const ClassInfo *cls = ClassInfo::FindClass(o_getClassName());
|
||||
auto thiz = (VM::Instance*)(this);
|
||||
Array wanted = Array::Create();
|
||||
Array props = ret.toArray();
|
||||
for (ArrayIter iter(props); iter; ++iter) {
|
||||
String name = iter.second().toString();
|
||||
if (o_exists(name, o_getClassName())) {
|
||||
ClassInfo::PropertyInfo *p = cls->getPropertyInfo(name);
|
||||
bool visible, accessible, unset;
|
||||
thiz->getProp(m_cls, name.get(), visible, accessible, unset);
|
||||
if (accessible && !unset) {
|
||||
String propName = name;
|
||||
if (p && (p->attribute & ClassInfo::IsPrivate)) {
|
||||
propName = concat4(s_zero, o_getClassName(), s_zero, name);
|
||||
VM::Slot propInd =
|
||||
m_cls->getDeclPropIndex(m_cls, name.get(), accessible);
|
||||
if (accessible && propInd != VM::kInvalidSlot) {
|
||||
if (m_cls->m_declProperties[propInd].m_attrs & VM::AttrPrivate) {
|
||||
propName = concat4(s_zero, o_getClassName(), s_zero, name);
|
||||
}
|
||||
}
|
||||
wanted.set(propName, const_cast<ObjectData*>(this)->
|
||||
o_getUnchecked(name, o_getClassName()));
|
||||
o_getImpl(name, RealPropUnchecked, true, o_getClassName()));
|
||||
} else {
|
||||
raise_warning("\"%s\" returned as member variable from "
|
||||
"__sleep() but does not exist", name.data());
|
||||
@@ -859,16 +702,6 @@ ObjectData *ObjectData::clone() {
|
||||
return instance->cloneImpl();
|
||||
}
|
||||
|
||||
Variant ObjectData::o_getError(CStrRef prop, CStrRef context) {
|
||||
raise_notice("Undefined property: %s::$%s", o_getClassName().data(),
|
||||
prop.data());
|
||||
return uninit_null();
|
||||
}
|
||||
|
||||
Variant ObjectData::o_setError(CStrRef prop, CStrRef context) {
|
||||
return uninit_null();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// magic methods that user classes can override, and these are default handlers
|
||||
// or actions to take:
|
||||
@@ -893,10 +726,6 @@ Variant ObjectData::t___get(Variant v_name) {
|
||||
return uninit_null();
|
||||
}
|
||||
|
||||
Variant *ObjectData::___lval(Variant v_name) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Variant ObjectData::offsetGet(Variant key) {
|
||||
assert(instanceof(SystemLib::s_ArrayAccessClass));
|
||||
const VM::Func* method = m_cls->lookupMethod(s_offsetGet.get());
|
||||
@@ -919,11 +748,6 @@ Variant ObjectData::t___unset(Variant v_name) {
|
||||
return uninit_null();
|
||||
}
|
||||
|
||||
bool ObjectData::o_propExists(CStrRef s, CStrRef context /* = null_string */) {
|
||||
Variant *t = o_realProp(s, RealPropExist, context);
|
||||
return t;
|
||||
}
|
||||
|
||||
Variant ObjectData::t___sleep() {
|
||||
clearAttribute(HasSleep);
|
||||
return uninit_null();
|
||||
|
||||
@@ -43,22 +43,13 @@ namespace VM {
|
||||
extern StaticString ssIterator;
|
||||
|
||||
/**
|
||||
* Base class of all user-defined classes. All data members and methods in
|
||||
* this class should start with "o_" or "os_" to avoid name conflicts.
|
||||
* Base class of all PHP objects and PHP resources.
|
||||
*
|
||||
* Calling sequence:
|
||||
*
|
||||
* 1. Statically resolved properties and methods will be statically called.
|
||||
* 2. Dynamic properties:
|
||||
* 1. Properties:
|
||||
* o_get() -> t___get() as fallback
|
||||
* o_lval() -> t___get() as fallback (!really)
|
||||
* o_set() -> t___set() as fallback
|
||||
* 3. Dynamic methods:
|
||||
* 2. Methods:
|
||||
* o_invoke() -> t___call() as fallback
|
||||
* 4. Auto-generated jump-tables:
|
||||
* o_realProp()
|
||||
* o_realPropPublic()
|
||||
* o_realPropPrivate() # non-virtual, only as needed
|
||||
*/
|
||||
class ObjectData : public CountableNF {
|
||||
public:
|
||||
@@ -69,7 +60,6 @@ class ObjectData : public CountableNF {
|
||||
UseGet = 0x0008, // __get()
|
||||
UseIsset = 0x0010, // __isset()
|
||||
UseUnset = 0x0020, // __unset()
|
||||
HasLval = 0x0040, // defines ___lval
|
||||
HasCall = 0x0080, // defines __call
|
||||
HasCallStatic = 0x0100, // defines __callStatic
|
||||
// The top 3 bits of o_attributes are reserved to indicate the
|
||||
@@ -82,11 +72,10 @@ class ObjectData : public CountableNF {
|
||||
};
|
||||
|
||||
enum {
|
||||
RealPropCreate = 1, // Property should be created if it doesnt exist
|
||||
RealPropWrite = 2, // Property could be modified
|
||||
RealPropNoDynamic = 4,// Dont return dynamic properties
|
||||
RealPropUnchecked = 8,// Dont check property accessibility
|
||||
RealPropExist = 16, // For property_exists
|
||||
RealPropCreate = 1, // Property should be created if it doesnt exist
|
||||
RealPropNoDynamic = 4, // Dont return dynamic properties
|
||||
RealPropUnchecked = 8, // Dont check property accessibility
|
||||
RealPropExist = 16, // For property_exists
|
||||
};
|
||||
|
||||
ObjectData(bool noId, VM::Class* type)
|
||||
@@ -152,15 +141,14 @@ class ObjectData : public CountableNF {
|
||||
CStrRef o_getClassName() const;
|
||||
CStrRef o_getParentName() const;
|
||||
virtual CStrRef o_getClassNameHook() const;
|
||||
static CStrRef GetParentName(CStrRef cls);
|
||||
virtual bool isResource() const { return false;}
|
||||
bool o_isClass(const char *s) const;
|
||||
int o_getId() const { return o_id;}
|
||||
|
||||
// overridable casting
|
||||
virtual bool o_toBoolean() const { return true;}
|
||||
virtual int64_t o_toInt64() const;
|
||||
virtual double o_toDouble() const { return o_toInt64();}
|
||||
virtual bool o_toBoolean() const { return true;}
|
||||
virtual int64_t o_toInt64() const;
|
||||
virtual double o_toDouble() const { return o_toInt64();}
|
||||
|
||||
void destruct();
|
||||
|
||||
@@ -172,18 +160,11 @@ class ObjectData : public CountableNF {
|
||||
return o_properties;
|
||||
}
|
||||
|
||||
Variant *o_realProp(CStrRef s, int flags,
|
||||
Variant* o_realProp(CStrRef s, int flags,
|
||||
CStrRef context = null_string) const;
|
||||
void *o_realPropTyped(CStrRef s, int flags,
|
||||
CStrRef context, DataType* type) const;
|
||||
Variant *o_realPropPublic(CStrRef s, int flags) const;
|
||||
bool o_exists(CStrRef s, CStrRef context = null_string) const;
|
||||
|
||||
Variant o_get(CStrRef s, bool error = true,
|
||||
CStrRef context = null_string);
|
||||
Variant o_getPublic(CStrRef s, bool error = true);
|
||||
Variant o_getUnchecked(CStrRef s, CStrRef context = null_string);
|
||||
|
||||
Variant o_i_setPublicWithRef(CStrRef s, CVarRef v);
|
||||
|
||||
Variant o_set(CStrRef s, CVarRef v);
|
||||
Variant o_set(CStrRef s, RefResult v);
|
||||
@@ -192,34 +173,12 @@ class ObjectData : public CountableNF {
|
||||
Variant o_set(CStrRef s, CVarRef v, CStrRef context);
|
||||
Variant o_set(CStrRef s, RefResult v, CStrRef context);
|
||||
Variant o_setRef(CStrRef s, CVarRef v, CStrRef context);
|
||||
Variant o_setPublic(CStrRef s, CVarRef v);
|
||||
Variant o_setPublic(CStrRef s, RefResult v);
|
||||
Variant o_setPublicRef(CStrRef s, CVarRef v);
|
||||
|
||||
Variant &o_lval(CStrRef s, CVarRef tmpForGet, CStrRef context = null_string);
|
||||
Variant *o_weakLval(CStrRef s, CStrRef context = null_string);
|
||||
|
||||
virtual void o_setArray(CArrRef properties);
|
||||
|
||||
virtual void o_getArray(Array &props, bool pubOnly = false) const;
|
||||
|
||||
Variant o_getError(CStrRef prop, CStrRef context);
|
||||
Variant o_setError(CStrRef prop, CStrRef context);
|
||||
/**
|
||||
* This is different from o_exists(), which is isset() semantics. This one
|
||||
* is property_exists() semantics. ie, accessibility is ignored, and declared
|
||||
* but unset properties still return true.
|
||||
*/
|
||||
bool o_propExists(CStrRef s, CStrRef context = null_string);
|
||||
void o_setArray(CArrRef properties);
|
||||
void o_getArray(Array &props, bool pubOnly = false) const;
|
||||
|
||||
static Object FromArray(ArrayData *properties);
|
||||
|
||||
CVarRef set(CStrRef s, CVarRef v);
|
||||
|
||||
// methods
|
||||
Variant o_invoke_ex(CStrRef clsname, CStrRef s,
|
||||
CArrRef params, bool fatal = true);
|
||||
|
||||
// method invocation with CStrRef
|
||||
Variant o_invoke(CStrRef s, CArrRef params, strhash_t hash = -1,
|
||||
bool fatal = true);
|
||||
@@ -241,7 +200,6 @@ class ObjectData : public CountableNF {
|
||||
virtual Variant t___call(Variant v_name, Variant v_arguments);
|
||||
virtual Variant t___set(Variant v_name, Variant v_value);
|
||||
virtual Variant t___get(Variant v_name);
|
||||
virtual Variant *___lval(Variant v_name);
|
||||
virtual bool t___isset(Variant v_name);
|
||||
virtual Variant t___unset(Variant v_name);
|
||||
virtual Variant t___sleep();
|
||||
@@ -256,15 +214,13 @@ class ObjectData : public CountableNF {
|
||||
CArrRef getProperties() const { return o_properties; }
|
||||
void initProperties(int nProp);
|
||||
private:
|
||||
static DECLARE_THREAD_LOCAL_NO_CHECK(int, os_max_id);
|
||||
ObjectData(const ObjectData &) { assert(false);}
|
||||
inline Variant o_getImpl(CStrRef propName, int flags,
|
||||
bool error = true, CStrRef context = null_string);
|
||||
static DECLARE_THREAD_LOCAL_NO_CHECK(int, os_max_id);
|
||||
template <typename T>
|
||||
inline Variant o_setImpl(CStrRef propName, T v,
|
||||
bool forInit, CStrRef context);
|
||||
template <typename T>
|
||||
inline Variant o_setPublicImpl(CStrRef propName, T v, bool forInit);
|
||||
public:
|
||||
static const bool IsResourceClass = false;
|
||||
|
||||
@@ -276,7 +232,6 @@ class ObjectData : public CountableNF {
|
||||
union {
|
||||
uint16_t u16;
|
||||
uint8_t u8[2];
|
||||
|
||||
} o_subclassData;
|
||||
|
||||
protected:
|
||||
|
||||
@@ -183,12 +183,12 @@ void tvCastToObjectInPlace(TypedValue* tv) {
|
||||
case KindOfDouble:
|
||||
case KindOfStaticString: {
|
||||
o = SystemLib::AllocStdClassObject();
|
||||
o->o_lval("scalar", -1) = tvAsVariant(tv);
|
||||
o->o_set("scalar", tvAsVariant(tv));
|
||||
break;
|
||||
}
|
||||
case KindOfString: {
|
||||
o = SystemLib::AllocStdClassObject();
|
||||
o->o_lval("scalar", -1) = tvAsVariant(tv);
|
||||
o->o_set("scalar", tvAsVariant(tv));
|
||||
tvDecRefStr(tv);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -112,11 +112,6 @@ Variant Object::o_get(CStrRef propName, bool error /* = true */,
|
||||
return m_px->o_get(propName, error, context);
|
||||
}
|
||||
|
||||
Variant Object::o_getPublic(CStrRef propName, bool error /* = true */) const {
|
||||
if (UNLIKELY(!m_px)) return warn_non_object();
|
||||
return m_px->o_getPublic(propName, error);
|
||||
}
|
||||
|
||||
Variant Object::o_set(CStrRef propName, CVarRef val,
|
||||
CStrRef context /* = null_string */) {
|
||||
if (!m_px) {
|
||||
@@ -138,32 +133,6 @@ Variant Object::o_set(CStrRef propName, RefResult val,
|
||||
return o_setRef(propName, variant(val), context);
|
||||
}
|
||||
|
||||
Variant Object::o_setPublic(CStrRef propName, CVarRef val) {
|
||||
if (!m_px) {
|
||||
setToDefaultObject();
|
||||
}
|
||||
return m_px->o_setPublic(propName, val);
|
||||
}
|
||||
|
||||
Variant Object::o_setPublicRef(CStrRef propName, CVarRef val) {
|
||||
if (!m_px) {
|
||||
setToDefaultObject();
|
||||
}
|
||||
return m_px->o_setPublicRef(propName, val);
|
||||
}
|
||||
|
||||
Variant Object::o_setPublic(CStrRef propName, RefResult val) {
|
||||
return o_setPublicRef(propName, variant(val));
|
||||
}
|
||||
|
||||
Variant &Object::o_lval(CStrRef propName, CVarRef tmpForGet,
|
||||
CStrRef context /* = null_string */) {
|
||||
if (!m_px) {
|
||||
setToDefaultObject();
|
||||
}
|
||||
return m_px->o_lval(propName, tmpForGet, context);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// output
|
||||
|
||||
|
||||
@@ -183,15 +183,10 @@ public:
|
||||
*/
|
||||
Variant o_get(CStrRef propName, bool error = true,
|
||||
CStrRef context = null_string) const;
|
||||
Variant o_getPublic(CStrRef propName, bool error = true) const;
|
||||
Variant o_set(CStrRef s, CVarRef v, CStrRef context = null_string);
|
||||
Variant o_set(CStrRef s, RefResult v, CStrRef context = null_string);
|
||||
Variant o_setRef(CStrRef s, CVarRef v, CStrRef context = null_string);
|
||||
Variant o_setPublic(CStrRef s, CVarRef v);
|
||||
Variant o_setPublic(CStrRef s, RefResult v);
|
||||
Variant o_setPublicRef(CStrRef s, CVarRef v);
|
||||
Variant &o_lval(CStrRef propName, CVarRef tmpForGet,
|
||||
CStrRef context = null_string);
|
||||
|
||||
/**
|
||||
* Input/Output
|
||||
*/
|
||||
|
||||
@@ -2445,17 +2445,6 @@ Variant Variant::o_get(CStrRef propName, bool error /* = true */,
|
||||
return null_variant;
|
||||
}
|
||||
|
||||
Variant Variant::o_getPublic(CStrRef propName, bool error /* = true */) const {
|
||||
if (m_type == KindOfObject) {
|
||||
return m_data.pobj->o_getPublic(propName, error);
|
||||
} else if (m_type == KindOfRef) {
|
||||
return m_data.pref->var()->o_getPublic(propName, error);
|
||||
} else if (error) {
|
||||
raise_notice("Trying to get property of non-object");
|
||||
}
|
||||
return null_variant;
|
||||
}
|
||||
|
||||
Variant Variant::o_set(CStrRef propName, CVarRef val,
|
||||
CStrRef context /* = null_string */) {
|
||||
if (m_type == KindOfObject) {
|
||||
@@ -2486,34 +2475,6 @@ Variant Variant::o_setRef(CStrRef propName, CVarRef val,
|
||||
return m_data.pobj->o_setRef(propName, val, context);
|
||||
}
|
||||
|
||||
Variant Variant::o_setPublic(CStrRef propName, CVarRef val) {
|
||||
if (m_type == KindOfObject) {
|
||||
} else if (m_type == KindOfRef) {
|
||||
return m_data.pref->var()->o_setPublic(propName, val);
|
||||
} else if (isObjectConvertable()) {
|
||||
setToDefaultObject();
|
||||
} else {
|
||||
// Raise a warning
|
||||
raise_warning("Attempt to assign property of non-object");
|
||||
return uninit_null();
|
||||
}
|
||||
return m_data.pobj->o_setPublic(propName, val);
|
||||
}
|
||||
|
||||
Variant Variant::o_setPublicRef(CStrRef propName, CVarRef val) {
|
||||
if (m_type == KindOfObject) {
|
||||
} else if (m_type == KindOfRef) {
|
||||
return m_data.pref->var()->o_setPublicRef(propName, val);
|
||||
} else if (isObjectConvertable()) {
|
||||
setToDefaultObject();
|
||||
} else {
|
||||
// Raise a warning
|
||||
raise_warning("Attempt to assign property of non-object");
|
||||
return uninit_null();
|
||||
}
|
||||
return m_data.pobj->o_setPublicRef(propName, val);
|
||||
}
|
||||
|
||||
Variant Variant::o_invoke(CStrRef s, CArrRef params, int64_t hash /* = -1 */) {
|
||||
if (m_type == KindOfObject) {
|
||||
return m_data.pobj->o_invoke(s, params, hash);
|
||||
@@ -2524,27 +2485,6 @@ Variant Variant::o_invoke(CStrRef s, CArrRef params, int64_t hash /* = -1 */) {
|
||||
}
|
||||
}
|
||||
|
||||
Variant Variant::o_root_invoke(CStrRef s, CArrRef params,
|
||||
int64_t hash /* = -1 */) {
|
||||
if (m_type == KindOfObject) {
|
||||
return m_data.pobj->o_invoke(s, params, hash);
|
||||
} else if (m_type == KindOfRef) {
|
||||
return m_data.pref->var()->o_root_invoke(s, params, hash);
|
||||
} else {
|
||||
throw_call_non_object(s);
|
||||
}
|
||||
}
|
||||
|
||||
Variant Variant::o_invoke_ex(CStrRef clsname, CStrRef s, CArrRef params) {
|
||||
if (m_type == KindOfObject) {
|
||||
return m_data.pobj->o_invoke_ex(clsname, s, params);
|
||||
} else if (m_type == KindOfRef) {
|
||||
return m_data.pref->var()->o_invoke_ex(clsname, s, params);
|
||||
} else {
|
||||
throw_call_non_object(s);
|
||||
}
|
||||
}
|
||||
|
||||
Variant Variant::o_invoke_few_args(CStrRef s, int64_t hash, int count,
|
||||
INVOKE_FEW_ARGS_IMPL_ARGS) {
|
||||
if (m_type == KindOfObject) {
|
||||
@@ -2558,22 +2498,6 @@ Variant Variant::o_invoke_few_args(CStrRef s, int64_t hash, int count,
|
||||
}
|
||||
}
|
||||
|
||||
Variant &Variant::o_lval(CStrRef propName, CVarRef tmpForGet,
|
||||
CStrRef context /* = null_string */) {
|
||||
if (m_type == KindOfObject) {
|
||||
return m_data.pobj->o_lval(propName, tmpForGet, context);
|
||||
} else if (m_type == KindOfRef) {
|
||||
return m_data.pref->var()->o_lval(propName, tmpForGet, context);
|
||||
} else if (isObjectConvertable()) {
|
||||
setToDefaultObject();
|
||||
return m_data.pobj->o_lval(propName, tmpForGet, context);
|
||||
} else {
|
||||
// Raise a warning
|
||||
raise_warning("Attempt to assign property of non-object");
|
||||
return const_cast<Variant&>(tmpForGet);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline ALWAYS_INLINE CVarRef Variant::SetImpl(Variant *self, T key,
|
||||
CVarRef v, bool isKey) {
|
||||
@@ -3081,68 +3005,26 @@ void Variant::serialize(VariableSerializer *serializer,
|
||||
}
|
||||
}
|
||||
|
||||
static void setValue(void *addr, DataType type,
|
||||
VariableUnserializer *uns, Variant &value) {
|
||||
value.unserialize(uns);
|
||||
switch (type) {
|
||||
case KindOfBoolean: *(bool*)addr = value; break;
|
||||
case KindOfInt64: *(int64_t*)addr = value; break;
|
||||
case KindOfDouble: *(double*)addr = value; break;
|
||||
case KindOfString:
|
||||
*(String*)addr = value.isString() ? value.getStringData() : nullptr;
|
||||
break;
|
||||
case KindOfArray:
|
||||
*(Array*)addr = value.isArray() ? value.getArrayData() : nullptr;
|
||||
break;
|
||||
case KindOfObject:
|
||||
*(Object*)addr = value.isObject() ? value.getObjectData() : nullptr;
|
||||
break;
|
||||
default:
|
||||
raise_error("Internal error in unserialize!");
|
||||
}
|
||||
}
|
||||
|
||||
static void unserializeProp(VariableUnserializer *uns,
|
||||
ObjectData *obj, CStrRef key,
|
||||
CStrRef context, CStrRef realKey,
|
||||
int nProp) {
|
||||
// Do a two-step look up
|
||||
int flags = ObjectData::RealPropWrite;
|
||||
DataType type;
|
||||
void *addr = obj->o_realPropTyped(key, flags, context, &type);
|
||||
if (addr) {
|
||||
if (UNLIKELY(type != KindOfUnknown)) {
|
||||
assert(uns->peek() != 'V' && uns->peek() != 'K');
|
||||
// This is a property which got type inferred.
|
||||
if (UNLIKELY(uns->peek() == 'O')) {
|
||||
// an object can be referred to by an 'r', so we
|
||||
// need to put the variant somewhere it will be available later
|
||||
// in case an 'r' refers back to it
|
||||
Variant &value = uns->addVar();
|
||||
setValue(addr, type, uns, value);
|
||||
} else {
|
||||
// we know its not going to be referred to by an 'R', because
|
||||
// we cant type-infer properties which are referenced, so
|
||||
// just unserialize to a temporary.
|
||||
Variant value;
|
||||
setValue(addr, type, uns, value);
|
||||
}
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
int flags = 0;
|
||||
Variant* t = obj->o_realProp(key, flags, context);
|
||||
if (!t) {
|
||||
// Dynamic property. If this is the first, and we're using HphpArray,
|
||||
// we need to pre-allocate space in the array to ensure the elements
|
||||
// dont move during unserialization.
|
||||
obj->initProperties(nProp);
|
||||
|
||||
addr = obj->o_realProp(realKey, ObjectData::RealPropCreate, context);
|
||||
if (!addr) {
|
||||
t = obj->o_realProp(realKey, ObjectData::RealPropCreate, context);
|
||||
if (!t) {
|
||||
// When accessing protected/private property from wrong context,
|
||||
// we could get NULL for o_realProp.
|
||||
throw Exception("Error in accessing property");
|
||||
}
|
||||
}
|
||||
((Variant*)addr)->unserialize(uns);
|
||||
t->unserialize(uns);
|
||||
}
|
||||
|
||||
void Variant::unserialize(VariableUnserializer *uns) {
|
||||
|
||||
@@ -885,22 +885,10 @@ class Variant : private VariantBase {
|
||||
return o_setRef(s, variant(v), context);
|
||||
}
|
||||
Variant o_setRef(CStrRef s, CVarRef v, CStrRef context = null_string);
|
||||
Variant o_getPublic(CStrRef propName, bool error = true) const;
|
||||
Variant o_setPublic(CStrRef s, CVarRef v);
|
||||
Variant o_setPublic(CStrRef s, RefResult v) {
|
||||
return o_setPublicRef(s, variant(v));
|
||||
}
|
||||
Variant o_setPublicRef(CStrRef s, CVarRef v);
|
||||
Variant &o_lval(CStrRef propName, CVarRef tmpForGet,
|
||||
CStrRef context = null_string);
|
||||
|
||||
Variant o_invoke(CStrRef s, CArrRef params, int64_t hash = -1);
|
||||
Variant o_root_invoke(CStrRef s, CArrRef params, int64_t hash = -1);
|
||||
Variant o_invoke_ex(CStrRef clsname, CStrRef s, CArrRef params);
|
||||
Variant o_invoke_few_args(CStrRef s, int64_t hash, int count,
|
||||
INVOKE_FEW_ARGS_DECL_ARGS);
|
||||
Variant o_root_invoke_few_args(CStrRef s, int64_t hash, int count,
|
||||
INVOKE_FEW_ARGS_DECL_ARGS);
|
||||
|
||||
template <typename T>
|
||||
inline ALWAYS_INLINE static CVarRef SetImpl(
|
||||
|
||||
@@ -722,19 +722,17 @@ bool BreakPointInfo::MatchClass(const char *fcls, const std::string &bcls,
|
||||
if (regex || !func || !*func) {
|
||||
return Match(fcls, 0, bcls, true, true);
|
||||
}
|
||||
if (strcasecmp(fcls, bcls.c_str()) == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const ClassInfo *clsInfo = ClassInfo::FindClass(bcls.c_str());
|
||||
if (clsInfo) {
|
||||
ClassInfo *foundClass;
|
||||
if (clsInfo->hasMethod(func, foundClass) && foundClass) {
|
||||
const char *name = foundClass->getName();
|
||||
return strcasecmp(fcls, name) == 0;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
StackStringData sdBClsName(bcls.c_str());
|
||||
VM::Class* clsB = VM::Unit::lookupClass(&sdBClsName);
|
||||
StackStringData sdFClsName(fcls);
|
||||
VM::Class* clsF = VM::Unit::lookupClass(&sdFClsName);
|
||||
if (!clsB) return false;
|
||||
if (clsB == clsF) return true;
|
||||
StackStringData sdFuncName(func);
|
||||
VM::Func* f = clsB->lookupMethod(&sdFuncName);
|
||||
if (!f) return false;
|
||||
return (f->baseCls() == clsF);
|
||||
}
|
||||
|
||||
bool BreakPointInfo::Match(const char *haystack, int haystack_len,
|
||||
|
||||
@@ -436,9 +436,9 @@ static void object_set(Variant &var, StringBuffer &key, CVarRef value,
|
||||
if (!assoc) {
|
||||
// We know it is stdClass, and everything is public (and dynamic).
|
||||
if (data.empty()) {
|
||||
var.getObjectData()->o_setPublic("_empty_", value);
|
||||
var.getObjectData()->o_set("_empty_", value);
|
||||
} else {
|
||||
var.getObjectData()->o_setPublic(data, value);
|
||||
var.getObjectData()->o_set(data, value);
|
||||
}
|
||||
} else {
|
||||
var.set(data, value);
|
||||
@@ -451,9 +451,9 @@ static void object_set(Variant &var, StringBuffer &key, RefResult value,
|
||||
if (!assoc) {
|
||||
// We know it is stdClass, and everything is public (and dynamic).
|
||||
if (data.empty()) {
|
||||
var.getObjectData()->o_setPublic("_empty_", value);
|
||||
var.getObjectData()->o_set("_empty_", value);
|
||||
} else {
|
||||
var.getObjectData()->o_setPublic(data, value);
|
||||
var.getObjectData()->o_set(data, value);
|
||||
}
|
||||
} else {
|
||||
var.set(data, value);
|
||||
|
||||
@@ -212,9 +212,10 @@ Variant f_get_parent_class(CVarRef object /* = null_variant */) {
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
const ClassInfo *classInfo = ClassInfo::FindClass(class_name.toString());
|
||||
if (classInfo) {
|
||||
CStrRef parentClass = classInfo->getParentClass();
|
||||
|
||||
VM::Class* cls = VM::Unit::lookupClass(class_name.toString().get());
|
||||
if (cls) {
|
||||
CStrRef parentClass = *(const String*)(&cls->parentRef());
|
||||
if (!parentClass.empty()) {
|
||||
return parentClass;
|
||||
}
|
||||
@@ -264,19 +265,18 @@ bool f_method_exists(CVarRef class_or_object, CStrRef method_name) {
|
||||
bool f_property_exists(CVarRef class_or_object, CStrRef property) {
|
||||
if (class_or_object.isObject()) {
|
||||
CStrRef context = ctxClassName();
|
||||
// Call o_exists for objects, to include dynamic properties.
|
||||
return class_or_object.toObject()->o_propExists(property, context);
|
||||
return (bool)class_or_object.toObject()->o_realProp(
|
||||
property, ObjectData::RealPropExist, context);
|
||||
}
|
||||
const ClassInfo *classInfo =
|
||||
ClassInfo::FindClass(get_classname(class_or_object));
|
||||
while (classInfo) {
|
||||
if (classInfo->hasProperty(property)) {
|
||||
return true;
|
||||
} else {
|
||||
classInfo = classInfo->getParentClassInfo();
|
||||
}
|
||||
|
||||
VM::Class* cls = VM::Unit::lookupClass(get_classname(class_or_object).get());
|
||||
bool accessible;
|
||||
VM::Slot propInd = cls->getDeclPropIndex(cls, property.get(), accessible);
|
||||
if (propInd != VM::kInvalidSlot) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
propInd = cls->lookupSProp(property.get());
|
||||
return (propInd != VM::kInvalidSlot);
|
||||
}
|
||||
|
||||
Variant f_get_object_vars(CVarRef object) {
|
||||
|
||||
@@ -1637,19 +1637,19 @@ Variant f_mysql_fetch_field(CVarRef result, int field /* = -1 */) {
|
||||
if (!(info = res->fetchFieldInfo())) return false;
|
||||
|
||||
Object obj(SystemLib::AllocStdClassObject());
|
||||
obj->set("name", *(info->name));
|
||||
obj->set("table", *(info->table));
|
||||
obj->set("def", *(info->def));
|
||||
obj->set("max_length", (int)info->max_length);
|
||||
obj->set("not_null", IS_NOT_NULL(info->flags)? 1 : 0);
|
||||
obj->set("primary_key", IS_PRI_KEY(info->flags)? 1 : 0);
|
||||
obj->set("multiple_key", info->flags & MULTIPLE_KEY_FLAG? 1 : 0);
|
||||
obj->set("unique_key", info->flags & UNIQUE_KEY_FLAG? 1 : 0);
|
||||
obj->set("numeric", IS_NUM(info->type)? 1 : 0);
|
||||
obj->set("blob", IS_BLOB(info->flags)? 1 : 0);
|
||||
obj->set("type", php_mysql_get_field_name(info->type));
|
||||
obj->set("unsigned", info->flags & UNSIGNED_FLAG? 1 : 0);
|
||||
obj->set("zerofill", info->flags & ZEROFILL_FLAG? 1 : 0);
|
||||
obj->o_set("name", *(info->name));
|
||||
obj->o_set("table", *(info->table));
|
||||
obj->o_set("def", *(info->def));
|
||||
obj->o_set("max_length", (int)info->max_length);
|
||||
obj->o_set("not_null", IS_NOT_NULL(info->flags)? 1 : 0);
|
||||
obj->o_set("primary_key", IS_PRI_KEY(info->flags)? 1 : 0);
|
||||
obj->o_set("multiple_key", info->flags & MULTIPLE_KEY_FLAG? 1 : 0);
|
||||
obj->o_set("unique_key", info->flags & UNIQUE_KEY_FLAG? 1 : 0);
|
||||
obj->o_set("numeric", IS_NUM(info->type)? 1 : 0);
|
||||
obj->o_set("blob", IS_BLOB(info->flags)? 1 : 0);
|
||||
obj->o_set("type", php_mysql_get_field_name(info->type));
|
||||
obj->o_set("unsigned", info->flags & UNSIGNED_FLAG? 1 : 0);
|
||||
obj->o_set("zerofill", info->flags & ZEROFILL_FLAG? 1 : 0);
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
@@ -578,7 +578,7 @@ static void pdo_stmt_construct(sp_PDOStatement stmt, Object object,
|
||||
if (!cls) {
|
||||
return;
|
||||
}
|
||||
object->set("queryString", stmt->query_string);
|
||||
object->o_set("queryString", stmt->query_string);
|
||||
TypedValue ret;
|
||||
VM::Instance* inst = static_cast<VM::Instance*>(object.get());
|
||||
inst->invokeUserMethod(&ret, cls->getCtor(), ctor_args.toArray());
|
||||
@@ -1930,12 +1930,12 @@ static bool do_fetch(sp_PDOStatement stmt, bool do_bind, Variant &ret,
|
||||
|
||||
case PDO_FETCH_OBJ:
|
||||
case PDO_FETCH_INTO:
|
||||
ret.toObject()->set(name, val);
|
||||
ret.toObject()->o_set(name, val);
|
||||
break;
|
||||
|
||||
case PDO_FETCH_CLASS:
|
||||
if ((flags & PDO_FETCH_SERIALIZE) == 0 || idx) {
|
||||
ret.toObject()->set(name, val);
|
||||
ret.toObject()->o_set(name, val);
|
||||
} else {
|
||||
#ifdef MBO_0
|
||||
ret = f_unserialize(val);
|
||||
|
||||
@@ -41,10 +41,10 @@ public:
|
||||
// overriding ResourceData
|
||||
virtual CStrRef o_getClassNameHook() const { return s_class_name; }
|
||||
|
||||
XmlDocWrapper(xmlDocPtr doc, const ClassInfo* cls)
|
||||
XmlDocWrapper(xmlDocPtr doc, CStrRef cls)
|
||||
: m_doc(doc), m_cls(cls) { }
|
||||
|
||||
const ClassInfo *getClass() { return m_cls; }
|
||||
CStrRef getClass() { return m_cls; }
|
||||
|
||||
void sweep() {
|
||||
if (m_doc) {
|
||||
@@ -54,7 +54,7 @@ public:
|
||||
~XmlDocWrapper() { XmlDocWrapper::sweep(); }
|
||||
private:
|
||||
xmlDocPtr m_doc;
|
||||
const ClassInfo* m_cls;
|
||||
String m_cls;
|
||||
};
|
||||
IMPLEMENT_OBJECT_ALLOCATION_NO_DEFAULT_SWEEP(XmlDocWrapper)
|
||||
|
||||
@@ -124,7 +124,7 @@ static Object create_text(CObjRef doc, xmlNodePtr node,
|
||||
CStrRef value, CStrRef ns,
|
||||
bool is_prefix, bool free_text) {
|
||||
Object obj = create_object(doc.getTyped<XmlDocWrapper>()->
|
||||
getClass()->getName(), Array(), false);
|
||||
getClass(), Array(), false);
|
||||
c_SimpleXMLElement *elem = obj.getTyped<c_SimpleXMLElement>();
|
||||
elem->m_doc = doc;
|
||||
elem->m_node = node->parent; // assign to parent, not node
|
||||
@@ -141,7 +141,7 @@ static Array create_children(CObjRef doc, xmlNodePtr root,
|
||||
static Object create_element(CObjRef doc, xmlNodePtr node,
|
||||
CStrRef ns, bool is_prefix) {
|
||||
Object obj = create_object(doc.getTyped<XmlDocWrapper>()->
|
||||
getClass()->getName(), Array(), false);
|
||||
getClass(), Array(), false);
|
||||
c_SimpleXMLElement *elem = obj.getTyped<c_SimpleXMLElement>();
|
||||
elem->m_doc = doc;
|
||||
elem->m_node = node;
|
||||
@@ -244,17 +244,22 @@ Variant f_simplexml_load_string(CStrRef data,
|
||||
return uninit_null();
|
||||
}
|
||||
|
||||
const ClassInfo *cls = ClassInfo::FindClass(!class_name.empty() ? class_name : s_SimpleXMLElement);
|
||||
if (cls == NULL) {
|
||||
throw_invalid_argument("class not found: %s", class_name.data());
|
||||
return uninit_null();
|
||||
}
|
||||
|
||||
if (!class_name->isame(s_SimpleXMLElement.get()) && !cls->derivesFrom(s_SimpleXMLElement, false)) {
|
||||
throw_invalid_argument("simplexml_load_string() expects parameter 2 to be a class name derived "
|
||||
"from SimpleXMLElement, '%s' given",
|
||||
class_name.data());
|
||||
return uninit_null();
|
||||
VM::Class* cls;
|
||||
if (!class_name.empty()) {
|
||||
cls = VM::Unit::lookupClass(class_name.get());
|
||||
if (!cls) {
|
||||
throw_invalid_argument("class not found: %s", class_name.data());
|
||||
return uninit_null();
|
||||
}
|
||||
if (!cls->classof(c_SimpleXMLElement::s_cls)) {
|
||||
throw_invalid_argument(
|
||||
"simplexml_load_string() expects parameter 2 to be a class name "
|
||||
"derived from SimpleXMLElement, '%s' given",
|
||||
class_name.data());
|
||||
return uninit_null();
|
||||
}
|
||||
} else {
|
||||
cls = c_SimpleXMLElement::s_cls;
|
||||
}
|
||||
|
||||
xmlDocPtr doc = xmlReadMemory(data.data(), data.size(), NULL, NULL, options);
|
||||
@@ -263,7 +268,7 @@ Variant f_simplexml_load_string(CStrRef data,
|
||||
return false;
|
||||
}
|
||||
|
||||
return create_element(Object(NEWOBJ(XmlDocWrapper)(doc, cls)),
|
||||
return create_element(Object(NEWOBJ(XmlDocWrapper)(doc, cls->nameRef())),
|
||||
root, ns, is_prefix);
|
||||
}
|
||||
|
||||
@@ -286,7 +291,6 @@ c_SimpleXMLElement::c_SimpleXMLElement(VM::Class* cb) :
|
||||
m_node(NULL), m_is_text(false), m_free_text(false),
|
||||
m_is_attribute(false), m_is_children(false), m_is_property(false),
|
||||
m_xpath(NULL) {
|
||||
setAttribute(HasLval);
|
||||
m_children = Array::Create();
|
||||
}
|
||||
|
||||
@@ -316,8 +320,7 @@ void c_SimpleXMLElement::t___construct(CStrRef data, int64_t options /* = 0 */,
|
||||
|
||||
xmlDocPtr doc = xmlReadMemory(xml.data(), xml.size(), NULL, NULL, options);
|
||||
if (doc) {
|
||||
m_doc = Object(NEWOBJ(XmlDocWrapper)(doc,
|
||||
ClassInfo::FindClass(s_SimpleXMLElement)));
|
||||
m_doc = Object(NEWOBJ(XmlDocWrapper)(doc, s_SimpleXMLElement));
|
||||
m_node = xmlDocGetRootElement(doc);
|
||||
if (m_node) {
|
||||
m_children = create_children(m_doc, m_node, ns, is_prefix);
|
||||
@@ -480,7 +483,7 @@ Object c_SimpleXMLElement::t_children(CStrRef ns /* = "" */,
|
||||
}
|
||||
|
||||
Object obj = create_object(m_doc.getTyped<XmlDocWrapper>()->
|
||||
getClass()->getName(), Array(), false);
|
||||
getClass(), Array(), false);
|
||||
c_SimpleXMLElement *elem = obj.getTyped<c_SimpleXMLElement>();
|
||||
elem->m_doc = m_doc;
|
||||
elem->m_node = m_node;
|
||||
@@ -542,7 +545,7 @@ Object c_SimpleXMLElement::t_attributes(CStrRef ns /* = "" */,
|
||||
}
|
||||
|
||||
Object obj = create_object(m_doc.getTyped<XmlDocWrapper>()->
|
||||
getClass()->getName(), Array(), false);
|
||||
getClass(), Array(), false);
|
||||
c_SimpleXMLElement *elem = obj.getTyped<c_SimpleXMLElement>();
|
||||
elem->m_doc = m_doc;
|
||||
elem->m_node = m_node;
|
||||
@@ -688,10 +691,6 @@ String c_SimpleXMLElement::t___tostring() {
|
||||
return "";
|
||||
}
|
||||
|
||||
Variant *c_SimpleXMLElement::___lval(Variant v_name) {
|
||||
return &m_children.lvalAt(v_name);
|
||||
}
|
||||
|
||||
Variant c_SimpleXMLElement::t___get(Variant name) {
|
||||
Variant ret = m_children[name];
|
||||
if (ret.isArray()) {
|
||||
@@ -700,7 +699,7 @@ Variant c_SimpleXMLElement::t___get(Variant name) {
|
||||
if (ret.isObject()) {
|
||||
c_SimpleXMLElement *elem = ret.toObject().getTyped<c_SimpleXMLElement>();
|
||||
Object obj = create_object(m_doc.getTyped<XmlDocWrapper>()->
|
||||
getClass()->getName(), Array(), false);
|
||||
getClass(), Array(), false);
|
||||
c_SimpleXMLElement *e = obj.getTyped<c_SimpleXMLElement>();
|
||||
e->m_doc = elem->m_doc;
|
||||
e->m_node = elem->m_node;
|
||||
@@ -1189,12 +1188,12 @@ static void libxml_error_handler(void *userData, xmlErrorPtr error) {
|
||||
|
||||
static Object create_libxmlerror(xmlError &error) {
|
||||
Object ret(NEWOBJ(c_LibXMLError)());
|
||||
ret->o_setPublic("level", error.level);
|
||||
ret->o_setPublic("code", error.code);
|
||||
ret->o_setPublic("column", error.int2);
|
||||
ret->o_setPublic("message", String(error.message, CopyString));
|
||||
ret->o_setPublic("file", String(error.file, CopyString));
|
||||
ret->o_setPublic("line", error.line);
|
||||
ret->o_set("level", error.level);
|
||||
ret->o_set("code", error.code);
|
||||
ret->o_set("column", error.int2);
|
||||
ret->o_set("message", String(error.message, CopyString));
|
||||
ret->o_set("file", String(error.file, CopyString));
|
||||
ret->o_set("line", error.line);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +88,6 @@ class c_SimpleXMLElement :
|
||||
virtual int64_t o_toInt64() const;
|
||||
virtual double o_toDouble() const;
|
||||
virtual Array o_toArray() const;
|
||||
virtual Variant *___lval(Variant v_name);
|
||||
private:
|
||||
xmlXPathContextPtr m_xpath;
|
||||
};
|
||||
|
||||
@@ -2714,8 +2714,11 @@ Variant c_SoapClient::t___setcookie(CStrRef name,
|
||||
CStrRef value /* = null_string */) {
|
||||
if (!value.isNull()) {
|
||||
m_cookies.set(name, CREATE_VECTOR1(value));
|
||||
} else if (o_exists("_cookies")) {
|
||||
m_cookies.remove(name);
|
||||
} else {
|
||||
const Variant* t = o_realProp("_cookies", RealPropUnchecked);
|
||||
if (t && t->isInitialized()) {
|
||||
m_cookies.remove(name);
|
||||
}
|
||||
}
|
||||
return uninit_null();
|
||||
}
|
||||
|
||||
@@ -1149,9 +1149,11 @@ static bool get_zval_property(Variant &object, const char* name,
|
||||
String sname(name);
|
||||
if (object.isObject()) {
|
||||
Object obj = object.toObject();
|
||||
if (Variant *t = obj->o_weakLval(sname)) {
|
||||
if (ret) ret->assignRef(*t);
|
||||
return true;
|
||||
if (Variant* t = obj->o_realProp(sname, ObjectData::RealPropUnchecked)) {
|
||||
if (t->isInitialized()) {
|
||||
if (ret) ret->assignRef(*t);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1314,7 +1316,7 @@ static void model_to_zval_object(Variant &ret, sdlContentModelPtr model,
|
||||
array.append(val);
|
||||
val = array;
|
||||
}
|
||||
ret.toObject()->set(String(model->u_element->name), val);
|
||||
ret.toObject()->o_set(String(model->u_element->name), val);
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1376,7 +1378,7 @@ static Variant to_zval_object_ex(encodeTypePtr type, xmlNodePtr data,
|
||||
return ret;
|
||||
}
|
||||
ret = create_object(ce, Array());
|
||||
ret.toObject()->set("_", master_to_zval_int(enc, data));
|
||||
ret.toObject()->o_set("_", master_to_zval_int(enc, data));
|
||||
} else {
|
||||
FIND_XML_NULL(data, ret);
|
||||
if (soap_check_xml_ref(ret, data)) {
|
||||
@@ -1411,13 +1413,13 @@ static Variant to_zval_object_ex(encodeTypePtr type, xmlNodePtr data,
|
||||
return ret;
|
||||
}
|
||||
redo_any = get_zval_property(ret, "any");
|
||||
ret.toObject()->set("any", uninit_null());
|
||||
ret.toObject()->o_set("any", uninit_null());
|
||||
} else {
|
||||
if (soap_check_xml_ref(ret, data)) {
|
||||
return ret;
|
||||
}
|
||||
ret = create_object(ce, Array());
|
||||
ret.toObject()->set("_", master_to_zval_int(sdlType->encode, data));
|
||||
ret.toObject()->o_set("_", master_to_zval_int(sdlType->encode, data));
|
||||
}
|
||||
} else {
|
||||
FIND_XML_NULL(data, ret);
|
||||
@@ -1428,7 +1430,7 @@ static Variant to_zval_object_ex(encodeTypePtr type, xmlNodePtr data,
|
||||
}
|
||||
if (sdlType->model) {
|
||||
if (redo_any) {
|
||||
ret.toObject()->set("any", uninit_null());
|
||||
ret.toObject()->o_set("any", uninit_null());
|
||||
}
|
||||
model_to_zval_object(ret, sdlType->model, data, sdl);
|
||||
if (redo_any) {
|
||||
@@ -1462,7 +1464,7 @@ static Variant to_zval_object_ex(encodeTypePtr type, xmlNodePtr data,
|
||||
xmlAddChild(dummy, text);
|
||||
Variant data = master_to_zval(attr->encode, dummy);
|
||||
xmlFreeNode(dummy);
|
||||
ret.toObject()->set(String(attr->name), data);
|
||||
ret.toObject()->o_set(String(attr->name), data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1481,11 +1483,12 @@ static Variant to_zval_object_ex(encodeTypePtr type, xmlNodePtr data,
|
||||
Variant prop;
|
||||
if (!get_zval_property(ret, (char*)trav->name, &prop)) {
|
||||
if (!trav->next || !get_node(trav->next, (char*)trav->name)) {
|
||||
ret.toObject()->set(String((char*)trav->name, CopyString), tmpVal);
|
||||
ret.toObject()->o_set(
|
||||
String((char*)trav->name, CopyString), tmpVal);
|
||||
} else {
|
||||
Array arr = Array::Create();
|
||||
arr.append(tmpVal);
|
||||
ret.toObject()->set(String((char*)trav->name, CopyString), arr);
|
||||
ret.toObject()->o_set(String((char*)trav->name, CopyString), arr);
|
||||
}
|
||||
} else {
|
||||
/* Property already exist - make array */
|
||||
@@ -1493,7 +1496,7 @@ static Variant to_zval_object_ex(encodeTypePtr type, xmlNodePtr data,
|
||||
/* Convert into array */
|
||||
Array arr = Array::Create();
|
||||
arr.append(prop);
|
||||
ret.toObject()->set(String((char*)trav->name, CopyString), arr);
|
||||
ret.toObject()->o_set(String((char*)trav->name, CopyString), arr);
|
||||
prop = arr;
|
||||
}
|
||||
/* Add array element */
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include "runtime/base/base_includes.h"
|
||||
#include "runtime/base/array/hphp_array.h"
|
||||
#include "util/util.h"
|
||||
#include "util/debug.h"
|
||||
#include "runtime/vm/core_types.h"
|
||||
@@ -952,7 +953,7 @@ Slot Class::getDeclPropIndex(Class* ctx, const StringData* key,
|
||||
// We didn't find a visible declared property in this's property map
|
||||
accessible = false;
|
||||
}
|
||||
// If ctx is an ancestor of this, check if ctx has a private method
|
||||
// If ctx is an ancestor of this, check if ctx has a private property
|
||||
// with the same name.
|
||||
if (ctx && classof(ctx)) {
|
||||
Slot ctxPropInd = ctx->lookupDeclProp(key);
|
||||
@@ -1728,7 +1729,6 @@ void Class::setODAttributes() {
|
||||
static StringData* sd__set = StringData::GetStaticString("__set");
|
||||
static StringData* sd__isset = StringData::GetStaticString("__isset");
|
||||
static StringData* sd__unset = StringData::GetStaticString("__unset");
|
||||
static StringData* sd___lval = StringData::GetStaticString("___lval");
|
||||
static StringData* sd__call = StringData::GetStaticString("__call");
|
||||
static StringData* sd__callStatic
|
||||
= StringData::GetStaticString("__callStatic");
|
||||
@@ -1739,7 +1739,6 @@ void Class::setODAttributes() {
|
||||
if (lookupMethod(sd__set )) { m_ODAttrs |= ObjectData::UseSet; }
|
||||
if (lookupMethod(sd__isset )) { m_ODAttrs |= ObjectData::UseIsset; }
|
||||
if (lookupMethod(sd__unset )) { m_ODAttrs |= ObjectData::UseUnset; }
|
||||
if (lookupMethod(sd___lval )) { m_ODAttrs |= ObjectData::HasLval; }
|
||||
if (lookupMethod(sd__call )) { m_ODAttrs |= ObjectData::HasCall; }
|
||||
if (lookupMethod(sd__callStatic)) { m_ODAttrs |= ObjectData::HasCallStatic; }
|
||||
}
|
||||
|
||||
@@ -26,9 +26,7 @@
|
||||
|
||||
#include <runtime/vm/core_types.h>
|
||||
#include <runtime/vm/repo_helpers.h>
|
||||
#include <runtime/base/array/hphp_array.h>
|
||||
#include <runtime/base/runtime_option.h>
|
||||
#include <runtime/ext_hhvm/ext_hhvm.h>
|
||||
#include <util/parser/location.h>
|
||||
#include <util/fixed_vector.h>
|
||||
#include <util/range.h>
|
||||
@@ -40,7 +38,9 @@ namespace HPHP {
|
||||
// Forward declaration.
|
||||
class ClassInfo;
|
||||
class ClassInfoVM;
|
||||
class HphpArray;
|
||||
class ObjectData;
|
||||
struct HhbcExtClassInfo;
|
||||
|
||||
namespace VM {
|
||||
|
||||
@@ -740,6 +740,10 @@ public:
|
||||
// the trait.
|
||||
bool declaredMethod(const Func* method);
|
||||
|
||||
bool hasConstant(const StringData* clsCnsName) const {
|
||||
return m_constants.contains(clsCnsName);
|
||||
}
|
||||
|
||||
TypedValue* clsCnsGet(const StringData* clsCnsName) const;
|
||||
DataType clsCnsType(const StringData* clsCnsName) const;
|
||||
void initialize() const;
|
||||
@@ -903,11 +907,6 @@ private:
|
||||
std::vector<ClassPtr> m_usedTraits;
|
||||
TraitAliasVec m_traitAliases;
|
||||
|
||||
// Methods.
|
||||
//
|
||||
// The m_methods map contains an entry for every method that can be
|
||||
// called in the context of this Class (but no private methods for
|
||||
// parent classes).
|
||||
MethodMap m_methods;
|
||||
|
||||
Slot m_traitsBeginIdx;
|
||||
|
||||
@@ -574,35 +574,6 @@ void Instance::raiseUndefProp(const StringData* key) {
|
||||
m_cls->name()->data(), key->data());
|
||||
}
|
||||
|
||||
void Instance::o_setArray(CArrRef properties) {
|
||||
for (ArrayIter iter(properties); iter; ++iter) {
|
||||
String k = iter.first().toString();
|
||||
Class* ctx = nullptr;
|
||||
|
||||
// If the key begins with a NUL, it's a private or protected property. Read
|
||||
// the class name from between the two NUL bytes.
|
||||
if (!k.empty() && k.charAt(0) == '\0') {
|
||||
int subLen = k.find('\0', 1) + 1;
|
||||
String cls = k.substr(1, subLen - 2);
|
||||
if (cls == "*") {
|
||||
// Protected.
|
||||
ctx = m_cls;
|
||||
} else {
|
||||
// Private.
|
||||
ctx = Unit::lookupClass(cls.get());
|
||||
if (!ctx) continue;
|
||||
}
|
||||
k = k.substr(subLen);
|
||||
}
|
||||
|
||||
CVarRef secondRef = iter.secondRef();
|
||||
setProp(ctx, k.get(), (TypedValue*)(&secondRef),
|
||||
secondRef.isReferenced());
|
||||
}
|
||||
// set public properties
|
||||
ObjectData::o_setArray(properties);
|
||||
}
|
||||
|
||||
void Instance::getProp(const Class* klass, bool pubOnly,
|
||||
const PreClass::Prop* prop,
|
||||
Array& props,
|
||||
@@ -635,41 +606,6 @@ void Instance::getProps(const Class* klass, bool pubOnly,
|
||||
}
|
||||
}
|
||||
|
||||
void Instance::o_getArray(Array& props, bool pubOnly /* = false */) const {
|
||||
// The declared properties in the resultant array should be a permutation of
|
||||
// propVec. They appear in the following order: go most-to-least-derived in
|
||||
// the inheritance hierarchy, inserting properties in declaration order (with
|
||||
// the wrinkle that overridden properties should appear only once, with the
|
||||
// access level given to it in its most-derived declaration).
|
||||
|
||||
// This is needed to keep track of which elements have been inserted. This is
|
||||
// the smoothest way to get overridden properties right.
|
||||
std::vector<bool> inserted(m_cls->numDeclProperties(), false);
|
||||
|
||||
// Iterate over declared properties and insert {mangled name --> prop} pairs.
|
||||
const Class* klass = m_cls;
|
||||
while (klass != nullptr) {
|
||||
getProps(klass, pubOnly, klass->m_preClass.get(), props, inserted);
|
||||
|
||||
const std::vector<ClassPtr> &usedTraits = klass->m_usedTraits;
|
||||
for (unsigned t = 0; t < usedTraits.size(); t++) {
|
||||
const ClassPtr& trait = usedTraits[t];
|
||||
getProps(klass, pubOnly, trait->m_preClass.get(), props, inserted);
|
||||
}
|
||||
|
||||
klass = klass->m_parent.get();
|
||||
}
|
||||
|
||||
// Iterate over dynamic properties and insert {name --> prop} pairs.
|
||||
if (o_properties.get() != nullptr && !o_properties.get()->empty()) {
|
||||
for (ArrayIter it(o_properties.get()); !it.end(); it.next()) {
|
||||
Variant key = it.first();
|
||||
CVarRef value = it.secondRef();
|
||||
props.addLval(key, true).setWithRef(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Variant Instance::t___destruct() {
|
||||
static StringData* sd__destruct = StringData::GetStaticString("__destruct");
|
||||
const Func* method = m_cls->lookupMethod(sd__destruct);
|
||||
|
||||
@@ -156,9 +156,6 @@ class Instance : public ObjectData {
|
||||
// Virtual ObjectData methods that we need to override
|
||||
|
||||
public:
|
||||
virtual void o_setArray(CArrRef properties);
|
||||
virtual void o_getArray(Array& props, bool pubOnly=false) const;
|
||||
|
||||
virtual Variant t___destruct();
|
||||
virtual Variant t___call(Variant v_name, Variant v_arguments);
|
||||
virtual Variant t___set(Variant v_name, Variant v_value);
|
||||
@@ -252,6 +249,8 @@ class Instance : public ObjectData {
|
||||
void unsetProp(Class* ctx, const StringData* key);
|
||||
|
||||
void raiseUndefProp(const StringData* name);
|
||||
|
||||
friend class ObjectData;
|
||||
};
|
||||
|
||||
inline Instance* instanceFromTv(TypedValue* tv) {
|
||||
@@ -269,9 +268,6 @@ class ExtObjectData : public HPHP::VM::Instance {
|
||||
: HPHP::VM::Instance(cls, false) {
|
||||
assert(!m_cls->callsCustomInstanceInit());
|
||||
}
|
||||
virtual void setRoot(ObjectData *r) {}
|
||||
virtual ObjectData *getRoot() { return this; }
|
||||
ObjectData *getBuiltinRoot() { return this; }
|
||||
};
|
||||
|
||||
template <int flags> class ExtObjectDataFlags : public ExtObjectData {
|
||||
|
||||
@@ -23,6 +23,10 @@
|
||||
#include <runtime/vm/translator/translator-inline.h>
|
||||
|
||||
namespace HPHP {
|
||||
|
||||
struct HhbcExtFuncInfo;
|
||||
struct HhbcExtClassInfo;
|
||||
|
||||
namespace VM {
|
||||
|
||||
ArrayData* new_array(int capacity);
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
// @generated by "php idl.php inc {input.idl.php} {output.inc}"
|
||||
|
||||
#if EXT_TYPE == 0
|
||||
"simplexml_load_string", T(Variant), S(0), "data", T(String), NULL, S(0), NULL, S(0), "class_name", T(String), "s:16:\"SimpleXMLElement\";", S(24), "\"SimpleXMLElement\"", S(0), "options", T(Int64), "i:0;", S(4), "0", S(0), "ns", T(String), "s:0:\"\";", S(7), "\"\"", S(0), "is_prefix", T(Boolean), "b:0;", S(4), "false", S(0), NULL, S(16384), "/**\n * ( excerpt from\n * http://php.net/manual/en/function.simplexml-load-string.php )\n *\n * Takes a well-formed XML string and returns it as an object.\n *\n * @data string A well-formed XML string\n * @class_name string You may use this optional parameter so that\n * simplexml_load_string() will return an object of the\n * specified class. That class should extend the\n * SimpleXMLElement class.\n * @options int Since PHP 5.1.0 and Libxml 2.6.0, you may also use\n * the options parameter to specify additional Libxml\n * parameters.\n * @ns string\n * @is_prefix bool\n *\n * @return mixed Returns an object of class SimpleXMLElement with\n * properties containing the data held within the xml\n * document. On errors, it will return FALSE.\n */",
|
||||
"simplexml_load_file", T(Variant), S(0), "filename", T(String), NULL, S(0), NULL, S(0), "class_name", T(String), "s:16:\"SimpleXMLElement\";", S(24), "\"SimpleXMLElement\"", S(0), "options", T(Int64), "i:0;", S(4), "0", S(0), "ns", T(String), "s:0:\"\";", S(7), "\"\"", S(0), "is_prefix", T(Boolean), "b:0;", S(4), "false", S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/function.simplexml-load-file.php\n * )\n *\n * Convert the well-formed XML document in the given file to an object.\n *\n * @filename string Path to the XML file\n *\n * Libxml 2 unescapes the URI, so if you want to pass\n * e.g. b&c as the URI parameter a, you have to call\n * simplexml_load_file(rawurlencode('http://example.com/\?a='\n * . urlencode('b&c'))). Since PHP 5.1.0 you don't need\n * to do this because PHP will do it for you.\n * @class_name string You may use this optional parameter so that\n * simplexml_load_file() will return an object of the\n * specified class. That class should extend the\n * SimpleXMLElement class.\n * @options int Since PHP 5.1.0 and Libxml 2.6.0, you may also use\n * the options parameter to specify additional Libxml\n * parameters.\n * @ns string\n * @is_prefix bool\n *\n * @return mixed Returns an object of class SimpleXMLElement with\n * properties containing the data held within the XML\n * document. On errors, it will return FALSE.\n */",
|
||||
"simplexml_load_string", T(Variant), S(0), "data", T(String), NULL, S(0), NULL, S(0), "class_name", T(String), "s:16:\"SimpleXMLElement\";", S(24), "\"SimpleXMLElement\"", S(0), "options", T(Int64), "i:0;", S(4), "0", S(0), "ns", T(String), "s:0:\"\";", S(7), "\"\"", S(0), "is_prefix", T(Boolean), "b:0;", S(4), "false", S(0), NULL, S(16384), "/**\n * ( excerpt from\n * http://php.net/manual/en/function.simplexml-load-string.php )\n *\n * Takes a well-formed XML string and returns it as an object.\n *\n * @data string A well-formed XML string\n * @class_name string You may use this optional parameter so that\n * simplexml_load_string() will return an object of the\n * specified class. That class should extend the\n * SimpleXMLElement class.\n * @options int Since PHP 5.1.0 and Libxml 2.6.0, you may also use\n * the options parameter to specify additional Libxml\n * parameters.\n * @ns string\n * @is_prefix bool\n *\n * @return mixed Returns an object of class SimpleXMLElement with\n * properties containing the data held within the xml\n * document. On errors, it will return FALSE.\n */",
|
||||
"simplexml_load_file", T(Variant), S(0), "filename", T(String), NULL, S(0), NULL, S(0), "class_name", T(String), "s:16:\"SimpleXMLElement\";", S(24), "\"SimpleXMLElement\"", S(0), "options", T(Int64), "i:0;", S(4), "0", S(0), "ns", T(String), "s:0:\"\";", S(7), "\"\"", S(0), "is_prefix", T(Boolean), "b:0;", S(4), "false", S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/function.simplexml-load-file.php\n * )\n *\n * Convert the well-formed XML document in the given file to an object.\n *\n * @filename string Path to the XML file\n *\n * Libxml 2 unescapes the URI, so if you want to pass\n * e.g. b&c as the URI parameter a, you have to call\n * simplexml_load_file(rawurlencode('http://example.com/\?a='\n * . urlencode('b&c'))). Since PHP 5.1.0 you don't need\n * to do this because PHP will do it for you.\n * @class_name string You may use this optional parameter so that\n * simplexml_load_file() will return an object of the\n * specified class. That class should extend the\n * SimpleXMLElement class.\n * @options int Since PHP 5.1.0 and Libxml 2.6.0, you may also use\n * the options parameter to specify additional Libxml\n * parameters.\n * @ns string\n * @is_prefix bool\n *\n * @return mixed Returns an object of class SimpleXMLElement with\n * properties containing the data held within the XML\n * document. On errors, it will return FALSE.\n */",
|
||||
"libxml_get_errors", T(Variant), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/function.libxml-get-errors.php )\n *\n * Retrieve array of errors.\n *\n * @return mixed Returns an array with LibXMLError objects if there\n * are any errors in the buffer, or an empty array\n * otherwise.\n */",
|
||||
"libxml_get_last_error", T(Variant), S(0), NULL, S(16384), "/**\n * ( excerpt from\n * http://php.net/manual/en/function.libxml-get-last-error.php )\n *\n * Retrieve last error from libxml.\n *\n * @return mixed Returns a LibXMLError object if there is any error\n * in the buffer, FALSE otherwise.\n */",
|
||||
"libxml_clear_errors", T(Void), S(0), NULL, S(16384), "/**\n * ( excerpt from http://php.net/manual/en/function.libxml-clear-errors.php\n * )\n *\n * libxml_clear_errors() clears the libxml error buffer.\n *\n * @return mixed No value is returned.\n */",
|
||||
"libxml_use_internal_errors", T(Boolean), S(0), "use_errors", T(Variant), "N;", S(2), "null", S(0), NULL, S(16384), "/**\n * ( excerpt from\n * http://php.net/manual/en/function.libxml-use-internal-errors.php )\n *\n * libxml_use_internal_errors() allows you to disable standard libxml\n * errors and enable user error handling.\n *\n * @use_errors mixed Whether to enable user error handling.\n *\n * @return bool This function returns the previous value of\n * use_errors.\n */",
|
||||
"libxml_set_streams_context", T(Void), S(0), "streams_context", T(Object), NULL, S(0), NULL, S(0), NULL, S(16384), "/**\n * ( excerpt from\n * http://php.net/manual/en/function.libxml-set-streams-context.php )\n *\n * Sets the streams context for the next libxml document load or write.\n *\n * @streams_context\n * resource\n * The stream context resource (created with\n * stream_context_create())\n *\n * @return mixed No value is returned.\n */",
|
||||
"libxml_disable_entity_loader", T(Boolean), S(0), "disable", T(Boolean), "b:1;", S(4), "true", S(0), NULL, S(16384), "/**\n * ( excerpt from\n * http://php.net/manual/en/function.libxml-disable-entity-loader.php )\n *\n * Disable/enable the ability to load external entities.\n *\n * @disable bool Disable (TRUE) or enable (FALSE) libxml extensions\n * (such as DOM, XMLWriter and XMLReader) to load\n * external entities.\n *\n * @return bool Returns the previous value.\n */",
|
||||
"libxml_use_internal_errors", T(Boolean), S(0), "use_errors", T(Variant), "N;", S(2), "null", S(0), NULL, S(16384), "/**\n * ( excerpt from\n * http://php.net/manual/en/function.libxml-use-internal-errors.php )\n *\n * libxml_use_internal_errors() allows you to disable standard libxml\n * errors and enable user error handling.\n *\n * @use_errors mixed Whether to enable user error handling.\n *\n * @return bool This function returns the previous value of\n * use_errors.\n */",
|
||||
"libxml_set_streams_context", T(Void), S(0), "streams_context", T(Object), NULL, S(0), NULL, S(0), NULL, S(16384), "/**\n * ( excerpt from\n * http://php.net/manual/en/function.libxml-set-streams-context.php )\n *\n * Sets the streams context for the next libxml document load or write.\n *\n * @streams_context\n * resource\n * The stream context resource (created with\n * stream_context_create())\n *\n * @return mixed No value is returned.\n */",
|
||||
"libxml_disable_entity_loader", T(Boolean), S(0), "disable", T(Boolean), "b:1;", S(4), "true", S(0), NULL, S(16384), "/**\n * ( excerpt from\n * http://php.net/manual/en/function.libxml-disable-entity-loader.php )\n *\n * Disable/enable the ability to load external entities.\n *\n * @disable bool Disable (TRUE) or enable (FALSE) libxml extensions\n * (such as DOM, XMLWriter and XMLReader) to load\n * external entities.\n *\n * @return bool Returns the previous value.\n */",
|
||||
|
||||
#elif EXT_TYPE == 1
|
||||
|
||||
|
||||
@@ -12294,7 +12294,7 @@ bool TestCodeRun::TestCompilation() {
|
||||
// lval on Variant
|
||||
MVCR("<?php function test() { return array();} reset(test());");
|
||||
|
||||
// variant.o_lval() needs lval() wrapper
|
||||
// obj->prop++ on Variant
|
||||
MVCR("<?php class A { public $prop = 1;} class B { public $prop = 5;} "
|
||||
"$a = 1; $a = new A(); $a->prop++; var_dump($a->prop);");
|
||||
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário