1. Hiphop安装
Hiphop 需要在centos 6.2以上支持可以,并且通过yum安装支持包比较好;
然后 cmake时,需要单独创建一个文件夹(如build),不要跟之前的文件混淆,否则编译好的内容会出现错误。
2. 动态加载
AllDynamic 在编译php 时,添加该属性就可以对动态内容进行加载,如require中用变量,默认是关闭的
-v “AllDynamic=true”
3. 守护进程日志不输出内容解决方法
Hiphop如果守护进程,进行日志配置,之前不输出内容,是由于使用了相对路径,hiphop在守护进程时,需要使用绝对路径才可以进行日志输出,如:
File =/export/hphp_project/xxxx.xxx.com_hphp_update_20120803/info.log
#access log settings
AccessLogDefaultFormat = %h %l %u %t \"%r\" %>s %b
Access {
* {
File =/export/hphp_project/xxx.xxx.com_hphp_update_20120803/access.log
Format = %h %l %u %t \"%r\" %>s %b
}
}
File这里配置的都是绝对路径即可
4. Hiphop 添加静态扩展
首先进入src/idl目录创建一个[extension name].idl.php文件
如:
hello.idl.php
:> hello.idl.php
在src/idl目录中创建
然后再执行schema.php ,生成idl模板,如:
/export/server/php/bin/php schema.php hello>hello.idl.php
生成好后,我们编写idl文件模板,可以参照里面的内容写方法和类,如:
DefineFunction(
array(
'name' =>"hello_world",
'desc' => "helloworld",
'return' => array(
'type' => Int64,
'desc' => "11,out helloworld!",
),
));
编辑好hello.idl.php后,我们先备份一下
Src/system/ext.inc和src/runtime/ext/ext.h这2个文件,因为在下面执行make后,这2个文件会被清空;
然后我们返回到src目录下,执行:
EXT=[existingextension name] make -C idl update命令,如:
EXT=hello make-C idl update
然后会生成ext_hello.cpp ext_hello.h hello.inc 在idl目录
在src/runtime/ext/profile/目录下生成extprofile_hello.h
在src/system目录下生成hello.inc文件
然后我们把ext_hello.cpp ext_hello.h这2个文件拷贝到src/runtime/ext目录下,然后我们为ext_hello.cpp里面添加实现,如我们修改ext_hello.cpp内容:
int64f_hello_world() {
printf("hello world");
return 11;
}
然后保存,编译好后,该方法会返回11 ,可进行测试。
然后我们把刚才备份的src/system/ext.inc和src/runtime/ext/ext.h拷贝回来覆盖现有的这2个文件,然后我们编辑src/system/ext.inc文件,在下面增加上一行:
#include "hello.inc"
我们需要增加扩展的inc文件,保存;
然后我们再修改src/runtime/ext/ext.h文件,添加上一行:
#include<runtime/ext/profile/extprofile_hello.h>
添加上我们扩展的extprofile的头文件
修改完这2个文件后,我们返回到主目录,创建一个build1目录,进入到build1目录中执行 cmake ../
然后cmake 完毕后执行make 安装完hiphop后我们在编译php文件会发现我们新加扩展的方法可以用了
5. Mongodb c++ client安装
下载mongodb-linux-x86_64-2.2.0-client.tgz,然后解压后后执行:
Scons
Scons需要预先安装
执行完scons后,打开build,下面有一个libmongoclient.a文件,这个文件cp 到$CMAKE_PREFIX_PATH的lib下
然后
cp -rmongo-cxx-driver-v2.2/src/mongo $CMAKE_PREFIX_PATH
如果执行g++编译:
g++ test_mongodb.cpp -I/export/dev/usr/include/ /export/dev/usr/lib/libmongoclient.a/usr/lib64/libboost_thread-mt.so /usr/lib64/libboost_filesystem.so/usr/lib64/libboost_program_options.so -o test_mongodb
6. hiphop 类实现
CMakeFiles/program.dir/cpp/001.cpp.o: Infunction `HPHP::pm_php$test_php(bool, HPHP::LVariableTable*,HPHP::Globals*)':\n001.cpp:(.text+0xbf): undefined reference to`HPHP::coo_Mongo()'\n001.cpp:(.text+0xc7): undefined reference to`HPHP::c_Mongo::create()'\ncollect2: ld \xb7\xb5\xbb\xd8 1\nmake[2]: ***[program] \xb4\xed\xce\xf3 1\nmake[1]: *** [CMakeFiles/program.dir/all]\xb4\xed\xce\xf3 2\nmake: *** [all] \xb4\xed\xce\xf3 2\n
compiling and linking CPP files took0'50" (50022 ms) wall time
当编译php时报了如上错误,说明没有coo_Mongo和c_Mongo::create() 的实现
这2个是在src/system/gen/sys目录下的dynamic_table_class.cpp中实现的,然后在dynamic_table_class.cpp中还有一些类的函数等注册信息,具体内容如下:
//这里是注册扩展类声明的位置coo_[扩展类名],如Mongo
ObjectData *coo_Mongo() {
return NEWOBJ(c_Mongo)();
}
//实现类注册
IMPLEMENT_CLASS(Mongo)
//接口表数组,必须
//第一参数是hash
//第二个参数是flag 0,1
//第三个参数是名字
//第四个参数是回调函数
//参照InstanceOfInfo 结构
extern const InstanceOfInfocw_Mongo$$instanceof_table[] = {
{0x414077AFA9BA239FLL,1,"Mongo",&cw_Mongo},
};
//这个也是必要的,内容所有的都一致,只是名字为扩展名称,如cw_[扩展名称]
const int cw_Mongo$$instanceof_index[] = {
1,
-1,0,
};
//调用信息
//第一参数调用方法
//第二个参数是调用最少参数
//第三个参数是调用参数总数
//第四个参数引用flags(不太清楚)
//参数参照CallInfo结构
//名字构成ci_扩展类名$$方法名称,如ci_Mongo$$__destruct,方法名称从生成的ext_扩展.h中的如果是普通方法把名字直接粘贴过来ci_Mongo$$函数名,如果是
extern const CallInfo ci_Mongo$$__destruct= { (void*)&c_Mongo::i___destruct, (void*)&c_Mongo::ifa___destruct, 0,4, 0x0000000000000000LL};
extern const CallInfo ci_Mongo$$__construct= { (void*)&c_Mongo::i___construct, (void*)&c_Mongo::ifa___construct,2, 4, 0x0000000000000000LL};
extern const CallInfo ci_Mongo$$___get = {(void*)&c_Mongo::i___get, (void*)&c_Mongo::ifa___get, 1, 4,0x0000000000000000LL};
//这里也是声明函数信息,所有内容几乎一致
//方法定义
Variant c_扩展类名称::i___函数名称(MethodCallPackage&mcp, CArrRef params) {
return invoke_meth_few_handler(mcp, params, &ifa___函数名称);
}
Variant c_Mongo::i___construct(MethodCallPackage&mcp, CArrRef params) {
return invoke_meth_few_handler(mcp, params, &ifa___construct);
}
Variantc_Mongo::i___destruct(MethodCallPackage &mcp, CArrRef params) {
return invoke_meth_few_handler(mcp, params, &ifa___destruct);
}
Variant c_Mongo::i___get(MethodCallPackage&mcp, CArrRef params) {
return invoke_meth_few_handler(mcp, params, &ifa___get);
}
Variantc_Mongo::ifa___construct(MethodCallPackage &mcp, int count,INVOKE_FEW_ARGS_IMPL_ARGS) {
if(UNLIKELY(mcp.obj == 0)) {
return ObjectData::ifa_dummy(mcp, count, INVOKE_FEW_ARGS_PASS_ARGS,ifa___construct, coo_Mongo);
}
c_Mongo *self ATTRIBUTE_UNUSED (static_cast<c_Mongo*>(mcp.obj));
//if (UNLIKELY(count<1 || count > 2)) return throw_toomany_arguments("__construct",1,2, 1);
CVarRef arg0(a0);
//if (count <= 1) return (self->t___construct(arg0));
CVarRef arg1(a1);
return (self->t___construct(arg0,arg1),null);
}
Variantc_Mongo::ifa___destruct(MethodCallPackage &mcp, int count, INVOKE_FEW_ARGS_IMPL_ARGS){
if(UNLIKELY(mcp.obj == 0)) {
return ObjectData::ifa_dummy(mcp, count, INVOKE_FEW_ARGS_PASS_ARGS,ifa___destruct, coo_Mongo);
}
c_Mongo *self ATTRIBUTE_UNUSED (static_cast<c_Mongo*>(mcp.obj));
if(UNLIKELY(count > 0)) return throw_toomany_arguments("__destruct",0, 1);
return (self->t___destruct());
}
Variantc_Mongo::ifa___get(MethodCallPackage &mcp, int count,INVOKE_FEW_ARGS_IMPL_ARGS) {
if(UNLIKELY(mcp.obj == 0)) {
return ObjectData::ifa_dummy(mcp, count, INVOKE_FEW_ARGS_PASS_ARGS,ifa___get, coo_Mongo);
}
c_Mongo *self ATTRIBUTE_UNUSED (static_cast<c_Mongo*>(mcp.obj));
//if (UNLIKELY(count != 1 )) returnthrow_toomany_arguments("___get", 1,1, 1);
CVarRef arg0(a0);
return (self->t___get(arg0));
}
extern const MethodCallInfoTablecw_Mongo$$call_info_table[] = {};
// {0x0D31D0AC229C615FLL, 0, 11, "__construct",&ci_Mongo$$__construct },
// {0x7F974836AACC1EF3LL, 1, 10, "__destruct", &ci_Mongo$$__destruct},
//};
//extern const intcw_Mongo$$call_info_index[] = {
// 3,
// -1,-1,-1,0,
//};
extern const intcw_Mongo$$call_info_index[] = {
};
c_Mongo *c_Mongo::create(String a0,Varianta1) {
CountableHelper h(this);
init();
t___construct(a0,a1);
clearNoDestruct();
return this;
}
extern const MethodCallInfoTablecw_Mongo$$call_info_table[];
extern const intcw_Mongo$$call_info_index[];
extern const InstanceOfInfocw_Mongo$$instanceof_table[];
extern const intcw_Mongo$$instanceof_index[];
const ObjectStaticCallbacks cw_Mongo = {
(ObjectData*(*)(ObjectData*))coo_Mongo,
cw_Mongo$$call_info_table,cw_Mongo$$call_info_index,
cw_Mongo$$instanceof_table,cw_Mongo$$instanceof_index,
&c_Mongo::s_class_name,
0,&ci_Mongo$$__construct,0,0,0x0,
&c_Mongo::s_cls
};
7. Hiphop编译错误:
make[5]: *** write jobserver: Bad filedescriptor. Stop.\nmake[5]: *** Waitingfor unfinished jobs....\nmake[5]: *** write jobserver: Bad filedescriptor. Stop.\nmake[4]: *** [CMakeFiles/program.dir/all]Error 2\nmake[3]: *** [all] Error 2\n
hphp failed
在扩展中添加mongo的连接在类函数中就会出现上面的问题,但是第二次编译后就没问题了
DBClientConnection c;
8. Hiphop编译错误
/export/dev/hiphop-php/src/system/gen/sys/dynamic_table_class.cpp:1309:error: prototype for 'HPHP::c_MongoCursor* HPHP::c_MongoCursor::create(HPHP::Variant,HPHP::String, HPHP::Array, HPHP::Array)' does not match any in class'HPHP::c_MongoCursor'
/export/dev/hiphop-php/src/runtime/ext/ext_mongo.h:55:error: candidate is: HPHP::c_MongoCursor*HPHP::c_MongoCursor::create(HPHP::Object, HPHP::String, HPHP::Array,HPHP::Array)
make[2]: ***[src/CMakeFiles/hphp_runtime_static.dir/system/gen/sys/dynamic_table_class.cpp.o]Error 1
make[1]: ***[src/CMakeFiles/hphp_runtime_static.dir/all] Error 2
make: *** [all] Error 2
当报这个错误时,是由于我们的dynamic_table_class.cpp文件的1309行的
c_MongoCursor::create…的类型错误了,所以参照
HPHP::c_MongoCursor*HPHP::c_MongoCursor::create(HPHP::Object, HPHP::String, HPHP::Array,HPHP::Array)提示把类型改过来就可以了
9. Hiphop编译错误
../../../bin/libhphp_runtime.a(dynamic_table_class.cpp.o):(.rodata+0x1360):undefined reference to`HPHP::c_MongoCursor::i_rewind(HPHP::MethodCallPackage&, HPHP::Arrayconst&)'
collect2: ld returned 1 exit status
make[2]: *** [src/hphp/hphp] Error 1
make[1]: ***[src/hphp/CMakeFiles/hphp.dir/all] Error 2
make[1]: *** Waiting for unfinishedjobs....
../../../bin/libhphp_runtime.a(dynamic_table_class.cpp.o):(.rodata+0x1360):undefined reference to`HPHP::c_MongoCursor::i_rewind(HPHP::MethodCallPackage&, HPHP::Arrayconst&)'
collect2: ld returned 1 exit status
当报这个错误时,提示没有引用i_rewind,说明我们未对i_rewind进行定义
我们只需要添加:
Variantc_MongoCursor::i_rewind(MethodCallPackage &mcp, CArrRef params) {
return invoke_meth_few_handler(mcp, params,&ifa_rewind);
}
声明一下,就可以了
10. Hiphop编译错误
HipHop Warning: Missing argument 1 for key() in test1.php online 6
当报这个错误时,是因为调用key()函数的方式出现了问题,如:
$a=new Mongo();
$a.key();
这样就会报上面的错误,因为php调用函数是用->
所以把$a.key()改为$a->key()就没有问题了
11. Hiphop创建对象指针
c_VectorIterator* it =NEWOBJ(c_VectorIterator)();
it->test();
12. hiphop编译错误
当编译php使用hiphop时,报了如下错误:
Core dumped: Segmentation fault
这可能是由于类调用方法不存在引发的段错误,如:
$a=new Mongo();
$a->key();
但是Mongo中没有key,那么就会出现上面的错误,段错误发生很多,这只是其中一种情况
13. Hiphop编译错误
error: 'c_Closure' was not declared in thisscope
当编译hiphop时,报了如上错误,是由于没有把c_Closure类的头文件引入进来,引入后就没问题了
14. Hiphop 的call_info_table和call_info_index
当使用hiphop 编译php时报出如下错误:
HipHop Fatal error: Unknown methodMongoCursor::rewind in test1.php on line 2
这里提示找不到方法rewind,是由于在dynamic_table_class.cpp这个类中定义MongoCursor的rewind中没有对call_info_table和call_info_index进行定义,这2个表都需要定义,否则会找不到函数;
call_info_index这个矩阵是有一定的规律的和call_info_table的数量是有关系的,和名字无关,所以当call_info_table数量相同时,所产生的call_info_index是一样的,现在找不到好的方法生成dynamic_table_class.cpp,所以可以借助一个php,在php中实现好类和函数,然后通过hiphop编译,然后在hiphop编译好的文件中找到cpp目录下的001.cpp(这里一个文件是由于在编译时定义cluster-count=1),然后找到相应的call_info_table和call_info_index拷贝到dynamic_table_class.cpp文件即可。
如:
extern const MethodCallInfoTablecw_myIterator___call_info_table[] = {
{0x7F974836AACC1EF3LL, 1, 10, "__destruct",&ci_myIterator_____destruct },
{0x6413CB5154808C44LL, 1, 5, "valid", &ci_myIterator___valid },
{0x337E695DE87C57C7LL, 1, 8, "key", &ci_myIterator___key },
{0x3C6D50F3BB8102B8LL, 1, 4, "next", &ci_myIterator___next },
{0x1670096FDE27AF6ALL, 1, 6, "rewind", &ci_myIterator___rewind },
{0x5B3A4A72846B21DCLL, 1, 7, "current", &ci_myIterator___current},
{0x0D31D0AC229C615FLL, 1, 11, "__construct",&ci_myIterator_____construct },
};
//这个和call_info_table的数量是有关系的
extern const intcw_myIterator___call_info_index[] = {
15,
-1,-1,-1,0,1,-1,-1,2,
3,-1,4,-1,5,-1,-1,6,
};
所以call_info_table和call_info_index是必要的
15. Hiphop支持Iterator
extern const InstanceOfInfocw_MongoCursor$$instanceof_table[] = {
{0x414077AFA9BA239FLL,1,"MongoCursor",&cw_MongoCursor},
{0x66679538C5E6F0A1LL,1,"Traversable",(constObjectStaticCallbacks*)2},
{0x0636A5F84AF9D29ELL,1,"Iterator",(constObjectStaticCallbacks*)2}
};
如果想让类支持Iterator,那么就在dynamic_table_class.cpp类中找到instanceof_table,然后加上{0x0636A5F84AF9D29ELL,1,"Iterator",(constObjectStaticCallbacks*)2}这句话就可以了
16. Hiphop类返回类,调用方法
如果在hiphop中需要返回一个类,并且调用它的方法,那么被返回类的方法一定要在call_info_table和call_info_index这2个数据中出现否则会报:
HipHop Fatal error: Unknown methodMongoCursor::rewind in test1.php on line 2
call_info_table和call_info_index是在dynamic_table_class.cpp类中添加
17. hiphop编译好的php目录结构
这个是编译好hiphop的目录结构
cls CMakeCache.txt CMakeFiles cmake_install.cmake CMakeLists.txt cpp Makefile php program sep_extensions.mk sys
cls中是当前编译的类的头文件
cpp是编译好的实现内容
18. hiphop编译错误
/export/hphp_project/test/php/test.cpp: Infunction 'HPHP::Variant HPHP::pm_php$test_php(bool, HPHP::LVariableTable*,HPHP::Globals*)':\n/export/hphp_project/test/php/test.cpp:21: error: 'classHPHP::GlobalVariables' has no member named'run_pm_php$test_php'\n/export/hphp_project/test/php/test.cpp:25: error: 'classHPHP::GlobalVariables' has no member named 'gvm_obj'\nmake[2]: ***[CMakeFiles/program.dir/php/test.cpp.o] Error 1\nmake[1]: ***[CMakeFiles/program.dir/all] Error 2\nmake: *** [all] Error 2\n
当报如上错误时,一般是编译文件出现冲突了,所以清理一遍编译目录,重新编译即可
19. Hiphop实现Iterator
在ext_mongo.h中:
#include <runtime/base/base_includes.h>
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
// class MongoCursor
FORWARD_DECLARE_CLASS_BUILTIN(MongoCursor);
class c_MongoCursor : public ExtObjectData{
public:
DECLARE_CLASS(MongoCursor, MongoCursor, ObjectData)
//这个是Iterator的游标
int64 m_position;
//这个是保存内容的集合
Array m_array;
//need to implement
public: c_MongoCursor(const ObjectStaticCallbacks *cb =&cw_MongoCursor);
public: ~c_MongoCursor();
public: void t___construct(CObjRef connection, CStrRef ns, CArrRef query= null_array, CArrRef fields = null_array);
DECLARE_METHOD_INVOKE_HELPERS(__construct);
public: Variant t_current();
DECLARE_METHOD_INVOKE_HELPERS(current);
public: int64 t_key();
DECLARE_METHOD_INVOKE_HELPERS(key);
public: void t_next();
DECLARE_METHOD_INVOKE_HELPERS(next);
public: void t_rewind();
DECLARE_METHOD_INVOKE_HELPERS(rewind);
public: bool t_valid();
DECLARE_METHOD_INVOKE_HELPERS(valid);
public: Variant t___destruct();
DECLARE_METHOD_INVOKE_HELPERS(__destruct);
//implemented by HPHP
public: c_MongoCursor *create(Object connection, String ns, Array query= null_array, Array fields = null_array);
};
}
在ext_mongo.cpp中:
#include <runtime/ext/ext_mongo.h>
#include<runtime/ext/ext_continuation.h>
#include <iostream>
using namespace std;
namespace HPHP {
///////////////////////////////////////////////////////////////////////////////
c_MongoCursor:: c_MongoCursor(constObjectStaticCallbacks *cb):ExtObjectData(cb){
cout<<"start"<<endl;
//在构造函数中初始化游标
m_position= 0LL;
m_array.append(new Variant("1"));
m_array.append(new Variant("2"));
m_array.append(new Variant("3"));
}
c_MongoCursor:: ~c_MongoCursor(){
cout<<"end"<<endl;
}
void c_MongoCursor::t___construct(CObjRef connection, CStrRef ns,CArrRef query, CArrRef fields){
//在(php)构造函数中初始化游标
m_position= 0LL;
//m_array.append(new Variant("1"));
//m_array.append(new Variant("2"));
//m_array.append(new Variant("3"));
cout<<"construct"<<endl;
}
Variant c_MongoCursor::t_current(){
cout<<"current"<<endl;
//m_array.rvalAt(m_position, AccessFlags::Error);返回当前位置的array
returnm_array.rvalAt(m_position, AccessFlags::Error);
}
int64 c_MongoCursor::t_key(){
cout<<"key"<<endl;
//返回当前位置
returnm_position;
}
void c_MongoCursor::t_next(){
cout<<"next"<<endl;
//对游标进行累加
++m_position;
}
//初始化
void c_MongoCursor::t_rewind(){
INSTANCE_METHOD_INJECTION_BUILTIN(MongoCursor,MongoCursor::rewind);
m_position = 0LL;
cout<<"rewind"<<endl;
}
//判断是否是最后一个对象
bool c_MongoCursor:: t_valid(){
cout<<"valid"<<endl;
returnisset(m_array, m_position);
}
Variant c_MongoCursor::t___destruct(){
cout<<"destruct"<<endl;
returnnull;
}
}
定义idl:
DefineFunction(
array(
'name' => 'current',
'return' => array(
'type' => Variant,
),
));
DefineFunction(
array(
'name' => 'key',
'return' => array(
'type' => Int64,
),
));
DefineFunction(
array(
'name' => 'next',
'return' => array(
'type' => null,
),
));
DefineFunction(
array(
'name' => 'rewind',
'return' => array(
'type' => null,
),
));
DefineFunction(
array(
'name' => 'valid',
'return' => array(
'type' => Boolean,
),
));
20. Hiphop编译失败
../../../bin/libhphp_runtime.a(ext_mongo.cpp.o):In function `HPHP::c_Mongo::c_Mongo(HPHP::ObjectStaticCallbacks const*)':
ext_mongo.cpp:(.text+0x2f): undefinedreference to `vtable for HPHP::c_Mongo'
../../../bin/libhphp_runtime.a(ext_mongo.cpp.o):In function `HPHP::c_MongoDB::c_MongoDB(HPHP::ObjectStaticCallbacks const*)':
ext_mongo.cpp:(.text+0xbf): undefinedreference to `vtable for HPHP::c_MongoDB'
collect2: ld returned 1 exit status
make[2]: *** [src/hphp/hphp] Error 1
make[1]: ***[src/hphp/CMakeFiles/hphp.dir/all] Error 2
make[1]: *** Waiting for unfinished jobs....
21. hiphop编译php失败
CMakeFiles/program.dir/php/test1.cpp.o: Infunction `HPHP::pm_php$test1_php(bool, HPHP::LVariableTable*,HPHP::Globals*)':\ntest1.cpp:(.text+0x0): multiple definition of`HPHP::pm_php$test1_php(bool, HPHP::LVariableTable*, HPHP::Globals*)'\nCMakeFiles/program.dir/cpp/001.cpp.o:001.cpp:(.text+0x0):first defined here\ncollect2: ld \xb7\xb5\xbb\xd8 1\nmake[2]: *** [program]\xb4\xed\xce\xf3 1\nmake[1]: *** [CMakeFiles/program.dir/all] \xb4\xed\xce\xf32\nmake: *** [all] \xb4\xed\xce\xf3 2\n
compiling and linking CPP files took1'05" (65239 ms) wall time
如果报这个错误,那么把输出编译内容清空一下重新编译即可
22. Hiphop编译错误
HipHop Fatal error: syntax error,unexpected T_OBJECT_OPERATOR in test_mongo.php on line 4
这个是因为php中定义的对象没有$
如:
test=new Mongo();
正确的应该是:
$test=new Mongo();
23. 通过php用函数模板生成dynamic_table_class.cpp内容
首先在php中定义好类和方法
然后通过HPHP_HOME/build/src/hphp/hphp 编译该php,编译好后,去编译后的目录的cpp文件夹下找到001.cpp(注意我们这里只编译一个php,cluster-count=1,这样主要为了方便查询)
然后我们打开001.cpp
从这里开始:
//cw_扩展名称___instanceof
extern const InstanceOfInfocw_Mongo___instanceof_table[] = {
{0x656B62D3A5CF04D9LL,1,"Mongo",&cw_Mongo},
};
…………………
中间内容省略
const ObjectStaticCallbacks cw_Mongo = {
(ObjectData*(*)(ObjectData*))coo_Mongo,
cw_Mongo___call_info_table,cw_Mongo___call_info_index,
cw_Mongo___instanceof_table,cw_Mongo___instanceof_index,
&c_Mongo::s_class_name,
0,&ci_Mongo_____construct,0,0,0x0,
&c_Mongo::s_cls
};
到这里结束拷贝到dynamic_table_class.cpp这个文件中,然后在上面加上:
ObjectData *coo_Mongo () {
return NEWOBJ(c_Mongo)();
}
IMPLEMENT_CLASS(Mongo)
这些内容即可,这2块拼接好后就是我们需要的class内容了,这里的mongo是扩展的名称,根据定义不同,可进行更改。
注:
dynamic_table_class.cpp通过hphp生成的变量名称ci和cw打头的和原生的有些区别,但是不影响,原生的dynamic_table_class.cpp生成的 ci和cw连接是用$$,hphp生成的是用____
如:
这个是hphp 生成的:
extern constInstanceOfInfo cw_Mongo___instanceof_table[] = {
{0x656B62D3A5CF04D9LL,1,"Mongo",&cw_Mongo},
};
这个是原生的:
extern const InstanceOfInfo cw_Mongo$$instanceof_table[] = {
{0x656B62D3A5CF04D9LL,1,"Mongo",&cw_Mongo},
};
24. Array 的头文件是Type_array.h
Array a=Array::Create();
Variant a1=Variant("1");
a.add(Variant("a1"),Variant("aa"));
a.add(Variant("a1"),Variant("ab"));
a.add(Variant("a1"),Variant("ac"));
for (ArrayIter iter(a); iter; ++iter) {
Variant vKey = iter.second();
cout<<vKey.toString().data()<<endl;
}
Array b=Array::Create();
b.set(Variant("b1"),Variant("ba"));
b.set(Variant("b1"),Variant("bb"));
b.set(Variant("b1"),Variant("bc"));
for (ArrayIter iter(b); iter; ++iter) {
Variant vKey = iter.second();
cout<<vKey.toString().data()<<endl;
}
Array c=Array::Create();
String key("name");
c.add(key,Variant("name1"));
key=String("value");
c.add(key,Variant(1));
key=String("tag");
c.add(key,Variant(0));
// c.add(String("name"),Variant("name1"));
// c.add(String("value"),Variant(1));
// c.add(String("tag"),Variant(0));
for (ArrayIter iter(c); iter; ++iter) {
Variant vKey = iter.second();
cout<<vKey.toString().data()<<endl;
}
其中,add或set的key都需要用hhvm的类型,具体参考type_array.h;
add和set的区别,add的key不保证唯一性,可以添加多条记录,set保证key唯一性,如果后面的再set同样key则覆盖key的value;
上面程序输出结果:
[huzg@BP-28-2-206192 hphp2]$ /export/dev_hphp2.0/hiphop-php_hzg/hphp/hhvm/hhvm test_hphp2.php
aa
ab
ac
bc
name1
1
0
这3个是add值:
aa
ab
ac
这是set值:
bc
25. Varint 的头文件Type_varint.h
26. 遍历hiphop的varint集合
for (ArrayIter iter(options); iter; ++iter){
Variant vKey = iter.second();
cout<<vKey.toString()<<endl;
}
27. CStrRef转换为char*
调用data方法
a. data();
28. hiphop新增扩展collection
#include<runtime/ext/profile/extprofile_collection.h>
29. Hiphop重新编译后,对Iterator扩展需要重新编译
当更新新版本的hiphop后,之前的iterator key 就无法应用,那么我们需要将之前编译好的php模板重新用hiphop新版的编译好,然后把内容复制到dynamic_table_class.cpp中,为什么要重新编译,因为instanceof_table和call_info_table的hash值变了,这个值需要和变量表中的一致,所以更新后需要重新编译复制过来,就不会出现问题了。
extern const InstanceOfInfocw_MongoCursor$$instanceof_table[] = {
{0x54E82965,1,"MongoCursor",&cw_MongoCursor},
{0x45E6F0A1,1,"Traversable",(const ObjectStaticCallbacks*)2},
{0x4AF9D29E,1,"Iterator",(const ObjectStaticCallbacks*)2},
};
extern const MethodCallInfoTablecw_MongoCursor$$call_info_table[] = {
{0x54808C44, 1, 5, "valid", &ci_MongoCursor$$valid },
{0x5373F906, 1, 5, "limit", &ci_MongoCursor$$limit },
{0x5E27AF6A, 0, 6, "rewind", &ci_MongoCursor$$rewind },
{0x0E1DBB2A, 1, 4, "sort", &ci_MongoCursor$$sort },
{0x024E8C51, 1, 3, "key", &ci_MongoCursor$$key },
{0x2ACC1EF3, 1, 10, "__destruct", &ci_MongoCursor$$__destruct },
{0x594564B4, 1, 4, "skip", &ci_MongoCursor$$skip },
{0x3B8102B8, 1, 4, "next", &ci_MongoCursor$$next },
{0x046B21DC, 1, 7, "current", &ci_MongoCursor$$current },
{0x229C615F, 1, 11, "__construct", &ci_MongoCursor$$__construct },
};
30. Htmlspecialchars不支持gb2312
GB2312 is not implemented yet
解决方法:
(1)修改$HPHP_HOME/src/runtime/base/server/transport.cpp文件
将 void Transport::prepareHeaders(boolcompressed, const void *data, int size)函数中的627行的:
string contentType = "text/html;charset="
+RuntimeOption::DefaultCharsetName;
改为:
stringcontentType = "text/html" ;
(2)修改$HPHP_HOME/src/runtime/base/string_util.cpp
将String StringUtil::HtmlEncode(CStrRefinput, QuoteStyle quoteStyle,
const char*charset, bool nbsp)函数中的333行的:
if(strcasecmp(charset, "ISO-8859-1") == 0) {
utf8 = false;
} else if (strcasecmp(charset,"UTF-8")) {
throw NotImplementedException(charset);
}
中的throwNotImplementedException(charset);注释掉,就不会抛HipHopFatal error: GB2312 is not implemented yet异常了。
31. hiphop编译php失败
CMakeFiles/program.dir/sys/literal_strings_0.no.cpp.o:In function `HPHP::init_literal_varstrings()':\nliteral_strings_0.no.cpp:(.text+0x0):multiple definition of`HPHP::init_literal_varstrings()'\nCMakeFiles/program.dir/sys/literal_strings_1.no.cpp.o:literal_strings_1.no.cpp:(.text+0x0):first defined here\ncollect2: ld \xb7\xb5\xbb\xd8 1\nmake[2]: *** [program]\xb4\xed\xce\xf3 1\nmake[1]: *** [CMakeFiles/program.dir/all] \xb4\xed\xce\xf32\nmake: *** [all] \xb4\xed\xce\xf3 2\n
compiling and linking CPP files took0'58" (58735 ms) wall time
hphp failed
当hiphop编译php失败报如上错误时,是由于编译的指定目录出现了冲突,所以把编译的指定目录清空后,重新编译就没有问题了。
编译路径如:
/export/dev/hiphop-php/build/src/hphp/hphptest_redis.php -k 1 --log=3 --cluster-count=1 -o /export/hphp_project/test
是–o 后面的路径
32. 新版本的dynamic_table_class.cpp的hash值变小了
如果更新版本后,注意每次添加新扩展时,需要对HASH值进行重新编译,因为旧的值在新版本中可能造成越界的警告:
如:
/export/dev/hiphop-php/src/system/gen/sys/dynamic_table_class.cpp:171:warning: overflow in implicit constant conversion
这里提示的是171行越界了,因为新版本的hash值变短了,所以之前旧的长所以造成了越界,
这是旧的hash值
extern const InstanceOfInfocw_MongoDB___instanceof_table[] = {
{0x5999BDEDF7C49E1FLL,1,"MongoDB",&cw_MongoDB},
};
这是新的hash值:
extern const InstanceOfInfocw_Mongo___instanceof_table[] = {
{0x5BD7C876,1,"Mongo",&cw_Mongo},
};
旧的(0x5999BDEDF7C49E1FLL)要比新的(0x5BD7C876)长,所以这里我们重新生成一遍,把就的hash值改了即可
需要改的变量为instanceof_table和call_info_table两个,改后就不会出现如上警告了
33. Hiphop类重复定义冲突错误
make[2]: *** No rule to make target`cls/Fake$0.h', needed by `CMakeFiles/program.dir/cpp/001.cpp.o'. Stop.\nmake[1]: ***[CMakeFiles/program.dir/all] Error 2\nmake: *** [all] Error 2\n
如果报了如Fake$0.h这样的错误,是由于在PHP文件中重复定义了类造成的,将一个删除即可。
34. Hiphop debug
cmake -DCMAKE_BUILD_TYPE=Debug .
make
35. 编译的php不存在
hphp:/export/dev/hiphop-php/src/util/job_queue.h:321:HPHP::JobQueueDispatcher<TJob, TWorker>::JobQueueDispatcher(int, bool,int, int, bool, void*, bool) [with TJob = OutputJob*, TWorker = OutputWorker]:Assertion `threadCount >= 1' failed
当执行
/export/dev/hiphop-php/build/src/hphp/hphpRedis1.php -k 1 --log=3 --cluster-count=1 -o /export/hphp_project/test
语句时报了如上错误,是由于Redis1.php不存在,改为正确的php路径的名字即可
36. Hiphop c++可以使用析构函数
在hiphop的类中继承Sweepable类就可以使用析构函数了,如:
在ext_redis.h中添加上Sweepable继承,
class c_Redis : public ExtObjectData,publicSweepable {
public:
……………………………………..
继承Sweepable了他后,就可以用~c_redis这个函数了
37. Php 的rawurlencode~不转换为%7E,hiphop的rawurlencode将~转换为%7E解决方法
在src/runtime/base/zend/zend_url.cpp中的这个方法url_raw_encode是进行编码的
char *url_raw_encode(const char *s, int&len) {
register int x, y;
unsigned char *str;
str= (unsigned char *)malloc(3 * len + 1);
for(x = 0, y = 0; len--; x++, y++) {
str[y] = (unsigned char) s[x];
if ((str[y] < '0' && str[y] != '-' && str[y] != '.')||
(str[y] < 'A' && str[y] > '9') ||
(str[y] > 'Z' && str[y] < 'a' && str[y] != '_') ||
(str[y] > 'z')) {
str[y++] = '%';
str[y++] = hexchars[(unsigned char) s[x] >> 4];
str[y] = hexchars[(unsigned char) s[x] & 15];
}
}
str[y] = '\0';
len= y;
return ((char *)str);
}
这里的str[y]是接受到的特殊字符是否进行编码,我们只需要在if最外层判断&&str[y]!=’~’即可,修改如下:
if (((str[y] < '0' && str[y] !='-' && str[y] != '.') ||
(str[y] < 'A' && str[y] > '9') ||
(str[y] > 'Z' && str[y] < 'a' && str[y] != '_') ||
(str[y] > 'z'))&&str[y]!=’~’)
38. 添加hiphop动态链接库
CMake/HPHPFind.cmake
添加:
target_link_libraries(${target} /export/dev_hphp/usr/lib/libhiredis.so)
target_link_libraries(${target}/export/dev_hphp/usr/lib/libmongoclient.a)
target_link_libraries(${target} /usr/lib64/libboost_thread-mt.so)
target_link_libraries(${target} /usr/lib64/libboost_filesystem.so)
target_link_libraries(${target}/usr/lib64/libboost_program_options.so)
后面的就是动态链接库的地址
39. Hiphop编译错误
../../../bin/libhphp_runtime.a(dynamic_table_class.cpp.o):In function `HPHP::c_MongoCursor::create(HPHP::Object, HPHP::String,HPHP::Array, HPHP::Array)':
dynamic_table_class.cpp:(.text+0x22455):undefined reference to `HPHP::c_MongoCursor::t___construct(HPHP::Objectconst&, HPHP::String const&, HPHP::Array const&, HPHP::Arrayconst&
报这个问题,如果存在t___construc但是编译找不到,那么清空编译目录重新编译
40. Hiphop编译错误
runningexecutable /export/dev_hphp/hiphop-php_hzg/src/hhvm/hhvm-vRepo.Authoritative=true -vRepo.Commit=false -vRepo.Local.Mode=r--vRepo.Local.Path=/export/hphp_project/test//hhvm.hhbc --file test_mongo.php...
sh:/export/dev_hphp/hiphop-php_hzg/src/hhvm/hhvm: 没有那个文件或目录
如果报上述错误,那么在HPHP_HOME下执行
Cmake .
Make –j 16生成HHVM即可
41. Hiphop编译php错误
当报如下错误时:
runningexecutable /export/dev/hiphop-php/src/hhvm/hhvm -vRepo.Authoritative=true-vRepo.Commit=false -vRepo.Local.Mode=r--vRepo.Local.Path=/export/hphp_project/test/hhvm.hhbc --file test_mongo.php...
sh:/export/dev/hiphop-php/src/hhvm/hhvm: No such file or directory
command failed:"/export/dev/hiphop-php/src/hhvm/hhvm -vRepo.Authoritative=true-vRepo.Commit=false -vRepo.Local.Mode=r--vRepo.Local.Path=/export/hphp_project/test/hhvm.hhbc --filetest_mongo.php"
all files savedin /export/hphp_project/test ...
running hphptook 0'00" (291 ms) wall time
这个是由于设置了USE_HHVM=1
这里把USE_HHVM=1环境变量清空,cmakemake 编译即可
42. Hiphop添加析构函数
在src\compiler\statement\Class_Statement.cpp文件下outputCPPImpl是生成头文件的代码
我们这个添加析构就是给类继承Sweepable,并且在c++的析构中调用t___destruct()即可;
我们在class_Statement.cpp文件的379行添加上:
public Sweepable
也就是如下代码:
cg_printf(" : public ObjectData,publicSweepable");
然后我们在592行下添加如下代码:
//add hiphop __destruct functoin
std::set <string> ::iteratordestruct_fun=done.find("__destruct ");
//__destrcut exists
if(destruct_fun!=done.end()){
cg_printf("public:~c_%s(){t___destruct();}\n",clsName);
}
上面的代码就是当类中有__destruct函数时,那么我们则在类里面添加
~c_类名(){t___destruct();}
添加c++析构函数,并调用php的析构即可;
done中保存了所有的类的声明的函数
43. hiphop 报undefinedreference to `HPHP::c_MongoDate::os_prop_table'错误
当hiphop报如下错误时:
undefined reference to`HPHP::c_MongoDate::os_prop_table'
由于该类用了属性,但是未引用
在dymanic_table_class.cpp最后加入:
const ClassPropTablec_MongoDate::os_prop_table = {
7,1,-1,-1,-1,-1,9,0,
cpt_hash_entries+0,0,cpt_table_entries+0,cpt_static_inits
};
这个就可以了
44. Hiphop报段错误
hphp:/export/dev/hiphop-php/src/compiler/analysis/type.cpp:82: static HPHP::TypePtrHPHP::Type::GetType(HPHP::Type::KindOf, const std::string&): Assertion`kindOf' failed.
Core dumped: Aborted
hphp failed
当编译php时报了如上错误,可能是由于system/xxx.inc内容和扩展的内容不匹配所造成的,所以检查新增的扩展和inc文件内容是否匹配
45. Hiphop最新版本支持包
Hiphop标准的gcc版本和boost
Gcc :4.6.1
Boost:1.50
这2个是facebook正在使用的,而且编译不会出现问题
46. Hiphop 支持namespace
修改/export/dev/hiphop-php/src/compiler/code_generator.cpp
364行的FormatLabel方法:
std::string CodeGenerator:: FormatLabel(const std::string &name) {
//cout<<name<<"---------------------------------"<<endl;
string ret;
ret.reserve(name.size());
for(size_t i = 0; i < name.size(); i++) {
unsigned char ch = name[i];
if ((ch >= 'a' && ch <= 'z') ||
(ch >= 'A' && ch <= 'Z') ||
(ch >= '0' && ch <= '9') || ch == '_') {
ret += ch;
}else {
char buf[10];
if(ch=='\\'){
snprintf(buf, sizeof(buf), "%02X",(int)ch);
}else{
snprintf(buf, sizeof(buf), "%s%02X",Option::LabelEscape.c_str(),
(int)ch);
}
ret += buf;
}
}
return ret;
}
Option::LabelEscape.c_str()是$
FormatLabel方法是把所有不包含在a-z,A-Z,0-9或_外的所有内容前加上$并把后面的字符通过%02X转换为16进制的ASCII码
我这里修改为:
if(ch=='\\'){
snprintf(buf, sizeof(buf), "%02X",(int)ch);
}else{
snprintf(buf, sizeof(buf), "%s%02X", Option::LabelEscape.c_str(),
(int)ch);
}
当不在数字、字母、下划线外的,如果字符为\\(右斜杠),那么不在其前面增加$只对其进行转义为5C,\\对应的ascii码是92
除此之外,还有在cpp中会添加上:
FORWARD_DECLARE_CLASS(类名)
所以这里也需要转义,否则找不到类:
生成FORWARD_DECLARE_CLASS的有3个地方:
(1)Src/compiler/code_generator.cpp中的
outputForwardDeclaration方法
是进行FORWARD_DECLARE_CLASS赋值的
(2) compiler/analysis/function_scope.cpp
outputCPPPreface该函数2184行FORWARD_DECLARE_CLASS
(3)compiler/analysis/variable_table.cpp
outputCPPGlobalVariablesHeader函数的866行FORWARD_DECLARE_CLASS
在生成代码后sys/ global_variables.cpp这个cpp文件中会生成FORWARD_DECLARE_CLASS代码
我们修改
compiler/analysis/variable_table.cpp的代码:
将866行代码:
cg_printf("FORWARD_DECLARE_CLASS(%s);\n",
varType->getName().c_str());
修改为:
string cls_name_new=CodeGenerator::FormatLabel(varType->getName());
cg_printf("FORWARD_DECLARE_CLASS(%s);\n",
cls_name_new.c_str());
首先进行一次格式化操作
47. Hiphop环境变量错误编译失败
当hiphop编译php时,编译失败,报如下错误:
compiling andlinking CPP files...
/export/hphp_project/test/cpp/001.cpp: In function \xe2\x80\x98HPHP::VariantHPHP::pm_php$test_diff1_php(bool, HPHP::LVariableTable*,HPHP::Globals*)\xe2\x80\x99:\n/export/hphp_project/test/cpp/001.cpp:25: error:\xe2\x80\x98x_onlysee\xe2\x80\x99 was not declared in thisscope\n/export/hphp_project/test/cpp/001.cpp:28: error: expected initializerbefore \xe2\x80\x98&\xe2\x80\x99token\n/export/hphp_project/test/cpp/001.cpp:29: error:\xe2\x80\x98tmp0\xe2\x80\x99 was not declared in this scope\nmake[2]: ***[CMakeFiles/program.dir/cpp/001.cpp.o] Error 1\nmake[1]: ***[CMakeFiles/program.dir/all] Error 2\nmake: *** [all] Error 2\n
这是由于环境变量错误造成的,所以重新设定的HPHP_HOME和HPHP_LIB即可
48. Hiphop 多核编译
在bin/run.sh中的make 后面加入-j 16 ,16是cpu数量
if [ -n "$HPHP_VERBOSE" ]; then
make -j 16 $MAKEOPTS > /dev/tty || exit $?
else
make -j 16 $MAKEOPTS || exit $?
Fi
49. Hiphop 20121224版编译错误解决
当编译时抛出了如下错误:
/export/dev_hhvm/hiphop-php_hzg/src/util/asm-x64.h:360:20:error: uninitialized const 'HPHP::VM::Transl::reg::rip' [-fpermissive]
解决方法:
在$HPHP/CMake/HPHPSetup.cmake 的118行,添加-fpermissive在编译即可, 下面标红位置
set(CMAKE_CXX_FLAGS "-fno-gcse-fno-omit-frame-pointer -ftemplate-depth-60 -Wall -Woverloaded-virtual-Wno-deprecated -Wno-strict-aliasing -Wno-write-strings -W no-invalid-offsetof -fno-operator-names-Wno-error=array-bounds -Wno-error=switch -std=gnu++0x -Werror=format-security -fpermissive"
50. hphp 生成扩展(静态编译)
首先创建src/idl/xxx.idl.php,如mongo.idl.php
然后返回到src 目录下,执行:
EXT=mongo make –C idl install|update
注:
如果按照原生写的makeFile会覆盖掉,system/ext.inc 和runtime/ext/ext.h文件的内容,所以我将src/idl/MakeFile的内容覆盖system/ext.inc和runtime/ext/ext.h的内容注释掉;
内容为:
21行的:
../system/ext.inc:idl_list.php $(IDL_PHPS)
20 @echo 'Generating $@'
21 #$(V)$(PHP) idl_list.php inc $@
22 $(V)touch ../compiler/builtin_symbols.cpp
35行的:
33 ../runtime/ext/ext.h: idl_list.php$(IDL_PHPS)
34 @echo 'Generating $@'
35 #$(V)$(PHP) idl_list.php ext $@
然后生成好后,在system/ext.inc 中加入新添加好的xxx.inc ,如mongo.inc;
如:
#include "mongo.inc"
然后在runtime/ext/ext.h中添加:
#include<runtime/ext/profile/extprofile_mongo.h>
添加好后,然后去$HPHP/build目录下进行编译;
由于在ext.inc 中添加了mongo.inc,所以mongo.inc的内容即为系统的内容;
在builtin_symbols.h 中即可把类,函数等信息初始化前加载在静态变量中,如:
static const char *ExtensionFunctions[];
static const char *ExtensionClasses[];
static const char *ExtensionConsts[];
static const char *ExtensionDeclaredDynamic[];
static const char *SystemClasses[];
static const char *HelperFunctions[];
编译好后,然后在system 目录下执行:
$HPHP --opts=none -t cpp -f sys -o ./gen t--input-dir . -i `find classes globals -name '*.php'`
即可将system/gen下的所有内容进行替换,如dymanic_table_class.cpp中的内容就会有mongo.inc中的类、变量等内容
然后在去$HPHP/build中进行make –j 16 编译,即可将扩展编译进去,这样扩展就编译成功和 hphp 成功耦合;
注意:
在生成好了system/gen下内容后,需要对ext_xxx.h对应的ext_xxx.cp中的内容进行实现,否则dymanic_table中是找不到实现的方法的,所以会报undefined reference 这样的错误
51. Hiphop20121224版本编译扩展undefinedreference to 错误解决方法
./../../bin/libext_hhvm.a(ext_mongo.ext_hhvm.cpp.o):In function `HPHP::fg_test_hello(HPHP::VM::ActRec*)':
ext_mongo.ext_hhvm.cpp:(.text+0x1a):undefined reference to `HPHP::f_test_hello()'
../../../bin/libext_hhvm.a(ext_mongo.ext_hhvm.cpp.o):In function `HPHP::new_Mongo_Instance(HPHP::VM::Class*)':
ext_mongo.ext_hhvm.cpp:(.text+0x153):undefined reference to `HPHP::c_Mongo::c_Mongo(HPHP::ObjectStaticCallbacksconst*)'
../../../bin/libext_hhvm.a(ext_mongo.ext_hhvm.cpp.o):In function `HPHP::tg_5Mongo___construct(HPHP::VM::ActRec*)':
ext_mongo.ext_hhvm.cpp:(.text+0x211):undefined reference to `HPHP::c_Mongo::t___construct(HPHP::String const&,HPHP::Variant const&)'
../../../bin/libext_hhvm.a(ext_mongo.ext_hhvm.cpp.o):In function `HPHP::tg_5Mongo___get(HPHP::VM::ActRec*)':
ext_mongo.ext_hhvm.cpp:(.text+0x5ff):undefined reference to `HPHP::c_Mongo::t___get(HPHP::Variant)'
../../../bin/libext_hhvm.a(ext_mongo.ext_hhvm.cpp.o):In function `HPHP::tg_5Mongo___destruct(HPHP::VM::ActRec*)':
ext_mongo.ext_hhvm.cpp:(.text+0x770):undefined reference to `HPHP::c_Mongo::t___destruct()'
../../../bin/libext_hhvm.a(ext_mongo.ext_hhvm.cpp.o):In function `HPHP::tg1_5Mongo___construct(HPHP::TypedValue*, HPHP::VM::ActRec*,long long, HPHP::ObjectData*)':
ext_mongo.ext_hhvm.cpp:(.text.unlikely+0xfd):undefined reference to `HPHP::c_Mongo::t___construct(HPHP::String const&,HPHP::Variant const&)'
../../../bin/libext_hhvm.a(ext_hhvm_infotabs.cpp.o):(.rodata+0x91b8):undefined reference to `HPHP::f_test_hello()'
collect2: ld returned 1 exit status
生成ext 扩展后,会在runtime/ext目录下生成如:
ext_mongo.h ext_mongo.cpp这2个文件,然后在ext_mongo.cpp中添加上实现;
然后我们在build目录下执行make –j 16 编译;编译完毕后,我们执行bin/generated_files.sh all
命令后,然后我们生成了hhvm 和hhvm_infotabs的内容;
但是编译后出现了为引用的信息,未引用的内容是ext_mongo.cpp的方法,由于在hiphop中是在dymanic_table中引用了这些内容,如果不对dymanic_table的内容进程生成,那么只有实现,没有引用就会产生这样的错误;
所以正常流程为:
(1) 先定义idl;
(2) 定义好idl后,去src 目录下执行EXT=mongo make –C idl install|update
(3) 将src/system/mongo.inc添加到ext.inc中进行引用;
(4) 将src/runtime/ext/extprofile_mongo.h 添加到ext.h中进行引用
(5) 去build目录下执行make –j 16,添加好ext.inc后,mongo的内容就为系统的内容了,类、函数、变量、常量等均会捕获到
(6) 执行完毕后,在去执行bin/generated_files.sh all,生成hhvm.cpp,更新hhvm_infotabs.cpp等
(7) 然后再去build目录重新build,这样扩展就加入到hhvm中了
52. 扩展模板生成类无构造函数错误解决方法
当通过idl生成扩展时报了如下错误;
PHP Fatal error: Uncaught exception 'Exception' with message'No constructor defined for class s_class' in/export/dev_hhvm/hiphop-php_hzg/src/idl/base.php:243
Stack trace:
#0 /export/dev_hhvm/hiphop-php_hzg/src/idl/test.idl.php(88):EndClass()
#1/export/dev_hhvm/hiphop-php_hzg/src/idl/idl.php(31):require('/export/dev_hhv...')
#2 {main}
thrown in /export/dev_hhvm/hiphop-php_hzg/src/idl/base.php on line 243
这是由于没有添加构造函数造成的问题;
DefineFunction(
array(
"name" =>"__construct",
"flags" =>HasDocComment,
"return" => array(
"type" => null,
),
));
加上这个就可以了
53. 生成扩展段错误,模板flags没加问题
在idl.php中
对于所有的class,function.defineProperty,defineConstant的声明flags是必须的,如果不加flags,那么编译好后,会抛出段错误,在compiler/builtin_symbols.cpp:189行,所以需要注意这一点,也就是最后在189行后的cname会是空指针
54. undefined reference 错误解决方法
../../../bin/libext_hhvm.a(ext_hhvm_infotabs.cpp.o):(.rodata+0x11e70):undefined reference to `HPHP::fg_test_hello(HPHP::VM::ActRec*)'
这个问题需要清空build ,重新编译
55. Idl模板实现接口
'ifaces' => array('Iterable','Countable'),
IsFinal用法,类定义(idl/collection.idl.php):
BeginClass(
array(
'name' =>"VectorIterator",
'ifaces' => array('Iterator'),
'desc' => "An iteratorimplementation for iterating over a Vector.",
'flags' => IsFinal | HasDocComment,
));
RefVariableArguments用法(idl/file.idl.php)
DefineFunction(
array(
'name' => "fscanf",
'desc' => “”,
'flags' => HasDocComment | RefVariableArguments,
…….
));
FunctionIsFoldable | NoEffect | NoInjection用法(idl/variable.idl.php):
DefineFunction(
array(
'name' =>"is_bool",
'desc' => "Finds whetherthe given variable is a boolean.",
'flags' => HasDocComment | FunctionIsFoldable | NoEffect| NoInjection,
…..
));
MixedVariableArguments | ContextSensitive用法(idl/function.idl.php)
DefineFunction(
array(
'name' =>"call_user_func_async",
'desc' => ".",
'flags' => HasDocComment | HipHopSpecific |MixedVariableArguments | ContextSensitive,
….
}
AllowIntercept用法(idl/apc.idl.php):
DefineFunction(
array(
'name' =>"apc_add",
'desc' => ".",
'flags' => HasDocComment | AllowIntercept,
…………….
}
HipHopSpecific| VariableArguments | HasOptFunction | NoProfile 用法(idl/fb.idl.php)
DefineFunction(
array(
'name' => "fb_call_user_func_safe",
'desc' => "",
'flags' => HasDocComment |HipHopSpecific | VariableArguments | HasOptFunction | NoProfile |ContextSensitive,
'opt' => "hphp_opt_fb_call_user_func",
…..
));
NoDefaultSweep用法(idl/domdocument.idl.php):
BeginClass(
array(
'name' => "DOMDocument",
'parent' => "DOMNode",
'bases' => array('Sweepable'),
'desc' => "",
'flags' => HasDocComment |NoDefaultSweep,
…
}
NeedsActRec用法(idl/error.idl.php):
DefineFunction(
array(
'name' => "debug_backtrace",
'desc' => "debug_backtrace() generates a PHP backtrace.",
'flags' => HasDocComment |NeedsActRec,
……..
'taint_observer' => false,
));
56. idl Flags 配置
functionflags:
HasDocComment
HasOptFunction
MixedVariableArguments
RefVariableArguments
VariableArguments
NoEffect
FunctionIsFoldable
ContextSensitive
NeedsActRec
Classflags:
Class method:
IsAbstract
IsProtected
IsPrivate
IsStatic
Class properties:
IsProtected
IsPrivate
IsStatic
57. Hiphop char 转换为Variant乱码
Char * a=malloc(sizeof(char));
如a 的值为”aaaddd”
将a转为hiphop 的variant
Variant(a)
但是这样转换后,有时候会产生乱码,所以我们需要先将char 指针等内容先转换为c++的
String ,然后将string 的值转换为Variant这样就不会产生乱码了
如:
Char a[3]=”abc”;
String b=a;
Varaint c=Varaint(b);
58. Hiphop ext扩展错误提示和异常
在cpp扩展代码中写入:
raise_warning(“warning content”);
raise_error(“error content!”);
59. 设置编码
Server {
DefaultCharsetName = GBK
}
60. Hiphop soap
Hiphop soap基本功能可支持,但是不支持no-wsdl模式,但是一般的情况下,一般都是使用wsdl模式;
SOAPFault php 和hiphop 抛出异常模式些许差异;但是都可以提示错误;
61. 执行generated_files.sh hhvm报错
当执行bin下的generated_files.sh hhvm报如下错误时
No object file to generate xxx.hhvm.cpp from,did you build first?
是因为新的扩展的.o文件不存在,所以需要重新编译可以找到该文件即可
这个内容是在generated_files.sh文件中这里实现的:
# $1 - Binary to pull symbols from
# $2 - .ext_hhvm.cpp file to build
make_hhvm()
{
echo "$1===$2"
[ !-f "$1" ] && check_err 1 "No object file to generate $2from, did you build first?"
[$VERBOSE -eq 1 ] && echo "Generating $2"
$HHVM gen_ext_hhvm.php $2 . /dev/null /dev/null "" $1
check_err $? "Failed generating $2"
}
62. Hiphop 扩展的函数名必须是小写
执行generated_files.sh hhvm
报了如下错误,因为function的名字有大写(这是有问题的)需要完善
Extension function name must be alllowercase: Ice_initialize
ext_hhvm generation failed
ERROR # 1 : Failed generating../ext/ext_ice.ext_hhvm.cpp
报这个错误的是:
是这个src/runtime/ext_hhvm/gen_lib.php文件中252行
if ($this->name != strtolower($this->name)){
echo "Extension function name must be all " .
"lowercase: " . $this->name . "\n";
echo "ext_hhvm generation failed\n";
exit(1);
生成扩展时生成的函数名称也都变为了小写是在src/idl/base.php中进行转换的
不知道为何将方法的名称都转为了小写
经测试,idl中的函数的命名可以为小写,因为在编译好的hhvm中,对于方法的名称不区分大小写,最终都是识别到小写
63. Hiphop Idl 设置默认值
在设置idl 的参数时,最多可以有2个不设置默认值;
如果你有4个参数,你都不设置默认值,那么第三个、第四个就会报如下错误:
default argument missing for parameter 4
所以最好设置idl时,给函数的参数都设置默认值
64. HPHP::String 转换成std::String
HPHP::String是hiphop 自定义的一个String类,它不能之间强转为std::String
需要通过将HPHP::String转换成char* 然后转换为std::String
例:
Varint a;//是一个hphp:string类型
Std::string b=a.toString().data();
这样既可
65. CObjRef转成指定类型的指针
bool f_memcache_set_server_params(CObjRefmemcache, CStrRef host,) {
//将Object对象转换成指定类型
c_Memcache *memcache_obj =memcache.getTyped<c_Memcache>();
return memcache_obj->t_setserverparams(host, port, timeout,retry_interval,
status, failure_callback);
}
66. 实例化hiphop 已有的hiphop类对象,并调用构造函数
如:
Php 中定义了一个类:
Class A {
Public$a;
Public$b;
Publicfunction __construct($a,$b){
$this->a=$a;
$this->b=$b
}
}
当通过hhvm转换后,这个A的类会生成一个hiphop的类为:c_A
Hiphop 实例化A并且通过构造函数对其进行成员变量的封装:
Object f_getObjectClass(CVarRefv) {
Object *obj = new Object();
//string aa = "c_" + v.toString();
HPHP::CStrRef ss = v.toCStrRef();
Array* params=new Array();
params->append(Variant("aaaaaa"));
params->append(Variant("bbbbbb"));
/*第一个参数是类的名称如:c_A
第二个参数是构造函数的参数,这个必须得有带参的构造函数,否则值是设置不进去的,
而且参数是按顺序进行遍历的;
第三个参数是对对象进行构造函数初始化
*/
Object aa=create_object(ss,*params,true);
return aa;
}
在头文件中需要引入
#include<runtime/base/externals.h>
这个头文件,create_object函数在这个文件中进行声明的
Create_Object实现是在bytecode.cpp文件中1365行,这个是hhvm的实现
create_object在builtin_functions.cpp的1012行是对外的create_object接口函数,分支是走hhvm还是走hphp
67. 内存泄露问题
$str =time().'.'.rand(10000, 99999) ;
define('LOG_ID', $str ) ;
当一个变量调用2个函数进行连接时,然后用define方式定义为常量会造成内存泄露的问题;
将常量设置为全局变量就可以解决这个问题了
68. 获取对象的成员变量值和通过类名获取类的成员
Object f_icephp_defineproxy (CObjRefclassObj) {
/*
通过传入对象获取对象的成员集合
Vars是以key value 保存的
*/
Variant vars=f_get_object_vars(classObj);
/*
通过类名获取类下的所有成员名称
classObj->o_getClassName()获取类名的方法返回值为CStrRef在Type_object.h中
*/
Array varNames=f_get_class_vars(classObj->o_getClassName());
/*
遍历类成员的名称
*/
for(ArrayIter iter(varNames); iter; ++iter) {
/*
获取成员名称
*/
Variant vKey = iter.first();
/*
根据成员名称获取对象下该成员的值
*/
cout<<vKey.toString()<<":"<<vars[vKey].toString()<<endl;;
}
return NULL;
}
../runtime/ext/ext_class.h
/* 通过类名获取类下的成员名称的Array集合*/
Array f_get_class_vars(CStrRef class_name);
/*
通过传入对象获取对象的成员列表
保存内容为:keyvalue ,key是成员名称,value是成员值
Variant是返回的集合
*/
Variant f_get_object_vars(CVarRef object);
Ext_class.h是hiphop操作类的扩展;
Php 代码:
<?php
class A{
public $a;
public $b;
public $c;
public function __construct($a,$b,$c){
$this->a=$a;
$this->b=$b;
$this->c=$c;
}
}
$a=new A("aaa222","bbb333","cccccc");
$c=newA("aaa111","bbb222","cccccc333");
//echo $a;
//print_r($a);
//var_dump($a);
$b=get_object_vars($a);
$count=count($b);
echo $count;
var_dump($b);
echo $b["a"];
echo $b["b"];
icephp_defineproxy($a);
icephp_defineproxy($c);
?>
后端输出内容如下,已获取到对象值
a:aaa222|
b:bbb333|
c:cccccc|
a:aaa111|
b:bbb222|
c:cccccc333|
69. hiphop 抛出异常处理
(1) 简单的抛出异常处理
throw Exception(“Test throw Exception”);
或
Exception e=new Exception(“Test thorw Exception”);
调用抛出异常的方法后hiphop控制台输出:
HipHop Fatal error: Test thorw Exception
(2) 获取php中声明的异常类,抛出异常信息
Hiphop代码:
Objectf_icephp_defineproxy(CObjRef classname) {
Objectf_icephp_defineproxy(CObjRef classname)
Array*params=new Array();
params->append(Variant(300));
params->append(Variant("RpcExceptionerror msg!"));
/*
通过创建动态类根据类名构造一个异常类,但是这里需要注意的是:
一般用户类前会加上c_xxx,但是Exception的用户类没有c_,直接在php
中定义的是什么类名,那么这里在创建对象时也是用什么名称,这里需要
注意,否则会找不到类
*/
Objecte=create_object("com_xx_RpcException",*params,true);
throwe;
return NULL;
}
PHP代码:
class com_xx_RpcExceptionextends Exception
{
public function__construct($resultCode=0, $msg='')
{
$this->resultCode =$resultCode;
$this->msg = $msg;
}
public function ice_name()
{
return 'com::xx::RpcException';
}
public function __toString()
{
return$this->msg."|".$this->resultCode;
}
public $resultCode;
public $msg;
}
try{
icephp_defineproxy($a);
}catch(Exception $e){
echo $e;
}
调用后在页面输出:
RpcException error msg!|300
70. Hiphop idl常量定义问题
DefineConstant(
array(
'name' =>"IcePHP__t_int",
'type' => Variant,
)
);
这里的Type只支持如下几种类型:
case Type::KindOfBoolean:
case Type::KindOfInt64:
case Type::KindOfDouble:
case Type::KindOfString:
case Type::KindOfArray:
case Type::KindOfVariant:
cg_printf("(const char *)&%s,\n", varName.c_str());
break;
这个是在analyze_result.cpp 的3341行,他们都会转换成char类型,但是不能是Object类型的,否则在执行generate_files.sh的时候会报错误,而错误的原因就出现在常量问题;
71. Hiphop idl中不要用typeid做变量名
用typeid做参数名称,在编译的时候会报错误,所以在idl中定义变量名称时不要用typeid做关键字
72. Hiphop 通过变量名称获取变量对象
在ext_variable.cpp中的f_get_defined_vars函数获取所有的变量,返回一个Array,Array中存放的是key是变量名,value是对象
例子:
Array dvs=f_get_defined_vars();
Varianta=dvs["IcePHP__t_int"];
Object b=a.toObject();
PrimitiveInfo*pi=b.getTyped<PrimitiveInfo>();
cout<<"IcePHP__t_int:"<<pi->kind<<endl;
73. hiphop 持久化对象
g_persistentObjects是hiphop 定义的一个持久化对象的mapmap,是PersistentObjectStore类型,在execution_context.h中
set(const char *type, const char *name,ResourceData *obj)
set方法
type是类型
name是第二层key
obj 是继承ResourceData的类
get函数:
ResourceData *get(const char *type, constchar *name);
Type是类型:
Name是key,获取resoucedata的类型
下面是具体的例子:
class Ice_Communicator : publicSweepableResourceData{
public:Ice_Communicator(){
cp=NULL;
};
public:~Ice_Communicator(){};
public:Ice::CommunicatorPtr cp;
public:std::set<std::string> factoryWrapperClassSet;
public:IceObjectFactoryWrapperPtr ifwp;
};
pthread_t tid;
tid = pthread_self();
//获取tid
Varianttidv=Variant((int64)tid);
char *tidc=tidv.toString().data();
Ice_Communicator*ic=dynamic_cast<Ice_Communicator*>(g_persistentObjects->get("ice_c",tidc));
if(ic==NULL){
ic=new Ice_Communicator();
g_persistentObjects->set("ice_c",tidc, ic);
ic->cp=Ice::initialize();
}
74. Hiphop 性能问题须知
编译hiphop 时如果需要debug
那么加上
cmake -DCMAKE_BUILD_TYPE=Debug .
但是如果加上debug后,hiphop的cpu使用率会高一倍
所以在线上正式使用的时候,需要把debug去掉,这样性能可以提高一倍
cmake .
75. 编译好的二进制的hhvm找systemlib.php文件
当执行hhvm找不到systemlib.php文件时,是由于没有配置HPHP_LIB环境变量,
HPHP_LIB指向的是hphp的bin目录,systemlib.php文件就在bin目录下
76. Php中的unset是销毁对象函数
当在php代码中调用了unset函数会销毁当前对象触发析构函数;
如:
$a=new A();
Unset($a);
这样就触发了A的析构函数,销毁了该对象
$a=new A();
$a=null;
也会销毁对象
77. Hiphop 内存泄露总结
当涉及到使用hiphop的扩展类时,需要实例化一个对象指针:
如:
Class Test:public ExtObjectData,publicSweepable{
}
那么当在代码中进行实例化,需要用hiphop内置的宏NEWOBJ
例:
Test *test=NEWOBJ(TEST)();
这样可以控制内存,如果用自己的new Test()这样实例化,一般delete需要考虑很多因素,但是用NEWOBJ时,需要在扩展类后面继承上Sweepable类才可以回收调用析构函数,这样就匹配了,不会造成内存泄露;
NEWOBJ用法:
NEWOBJ(扩展类类名)(参数)
当在hiphop 自己的创建的类,那么就需要用new 和delete 进行匹配,否则会造成内存泄露;
在使用map时,如果是把值放入到对象中,那么map的second是存的值,这时的地址不是你的对象地址,如:
Test *test=new Test();
Std::map<std::string,Test> map;
Map[“1”]=*test;
注意,这里的map[1]存的value是test对象,而不是test这个对象的地址,当封装到map中后,map会给他分配一块独立的地址,所以再取时释放的也是map的地址,如果想用map存放上对象,并在后面释放,那么最好存对象指针
getTyped涉及内存泄露:
当使用getTyped进行类型转换时,getTyped中的类需要继承Sweapable,否则转换的对象不会被回收
p_cict = iceclassobj.getTyped<c_IcePHP_class>();
Array和Varaint如果用new 来实例化,那么需要对其进行delete回收对象,所以一般建议去创建值,如果非要用指针,那么就要注意回收:
Array array=Array::Create();//创建Array对象
Variant v=Variant();//创建Variant对象
78. 编码问题到底hhvm 运行报unknown Exception
部署hiphop 的时候首先打印一下语言:
echo $LANG
输出为:
zh_CN.UTF-8
这个是正确的,如果编码为
Zh-CN.gbk
这个横线应该是下划线,否则hiphop访问时会报unknown exception错误,这个很难发现,一定要注意
79. 共享内存对象
Hiphop中的APC使用共享内存对象实现的,所以xcache也采用该模式,在hiphop中的
SharedStore类是共享存储,并且通过newConcurrentTableSharedStore(0)进行实例化的;
SharedStore定义在src\runtime\base\shared\shared_store_base.h中
ConcurrentTableSharedStore 定义在src\runtime\base\shared\concurrent_shared_store.h中
ConcurrentTableSharedStore(id)构造函数中是id 一般来说一个下标即可;
ConcurrentTableSharedStore是SharedStore的子类
例:
SharedStore m_store = newConcurrentTableSharedStore(0) ;
//存值:
m_store ->store( name, value, ttl, true)
//具体实现:
/*
virtual bool store(CStrRef key, CVarRefval, int64 ttl,
bool overwrite = true
*/
//取值
m_store ->get(name, v);
详细可见源码;
80. Memcached超时问题解决
安装libmecached需要在1.0.1以上,目前安装的是1.0.5
安装后,然后将包替换到/export/dev_hhvm/usr下包括头文件和so文件
然后重新编译
用ldd build/src/hhvm/hhvm |grep memcached查看
libmemcached.so.9 =>/export/dev_hhvm/usr/lib/libmemcached.so.9
如果是9就对了,如果是7那么就是0.49版本的,老版本的不支持超时;
还有一点就是
$m->setOption(Memcached::OPT_RECV_TIMEOUT,1000);
$m->setOption(Memcached::OPT_SEND_TIMEOUT,1000);
$m->setOption(Memcached::OPT_RETRY_TIMEOUT,300);
$m->setOption(Memcached::OPT_CONNECT_TIMEOUT,1);
$m->addServer('10.1.2.3', 11211);
setOption 设置需要在addServer之前才可以生效,在addServer后不生效
81. 添加hhvm runtime option
在runtime_option.cpp中定义静态变量,设定初值
//第一层
Hdfmysql = config["MySQL"];
//第二层,MySQLReadOnly是静态变量,ReadOnly是mysql下的值
MySQLReadOnly =mysql["ReadOnly"].getBool();
调用时RuntimeOption:: MySQLReadOnly调用就可以获取了
Src/runtime/base/runtime_option.cpp
82. Freetds查找etc配置问题
Hhvm应用freetds时,需要找到他的动态链接库libsybdb.so;
libsybdb.so库可以放到任意位置,但是freetds的etc需要在一个已经安装的目录下,而etc也需要是这个目录下安装好的lib下的库才可以,所以有如下2种方式配置:
(1) 配置环境变量
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/freetds0.82/lib
红色部分是freetds 的动态链接库位置(也就是已经安装的freetds位置)
(2) 设置动态链接库
echo “/usr/local/freetds0.82/lib ” > /etc/ld.so.conf.d/hhvm.conf
ldconfig
这时候查看ldd hhvm|grep libsydbd.so就可以看到相应的路径了;
Freetds安装方法:
./configure--prefix=/usr/local/freetds0.82 --enable-msdblib --with-tdsver=5.0
83. 获取cpu核心数量
Process::GetCPUCount();
Src/util/process.h
MachineInfo类是机器信息在
Src/runtime/ext/ext_hotprofiler.cpp中
修改默认的ThreadCount数量:
默认hhvm中ThreadCount数量为50,在runtime_option.cpp中
//修改为默认cpu核数的一倍*2
int RuntimeOption::ServerThreadCount=50;//101行 定义变量
int RuntimeOption::ServerThreadCount = Process::GetCPUCount()<<1
….
ServerThreadCount =server["ThreadCount"].getInt32(50);//717行intcpucount=Process::GetCPUCount()<<1;
ServerThreadCount =server["ThreadCount"].getInt32(cpucount);//赋值操作
84. Hdf的getBool问题
如:
MySQL {
ReadOnly = false
}
这里ReadOnly = false后面不要加分号,如果加了分号后,那么则会匹配为true
Hiphop的getBool的逻辑是不是0,false,no,off就是true
boolHdf::getBool(bool defValue /* = false */) const {
const char *v = get();
//如果v是空指针,返回false
if (v == nullptr) return defValue;
//一般存在值即为true,因为不可能0,false,no,off共存,并且v这里永远为true, //因为strcmp不配置为非0,
return *v && strcmp(v, "0")&&
strcasecmp(v, "false") &&strcasecmp(v, "no") && strcasecmp(v, "off");
}
85. 获取网络传输对象
Transport *transport =g_context->getTransport();
transport->sendString (“test”,200);
第一个是内容,第二个是http_code
g_context是线程内部的上下文对象;
86. ___autoload 传入的参数为小写解决方法
Test_static.php:
<?php
function __autoload($name)
{
echo “className:”.$name."===\n";
require $name.".php";
//require "ConsultationConstract.php";
}
$timeout = ConsultationConstract::$GETCONSULTATION['timeout'];
echo $timeout;
?>
ConsultationConstract.php
<?php
class ConsultationConstract {
public static $GETCONSULTATION = array (
'timeout' => 3600
);
}
?>
默认的hhvm输出 echo “className:”.$name."===\n";
是小写的consultationconstract;
但我们需要的是ConsultationConstract;
目前解决方式是:
将compiler\expression\static_class_name.cpp的updateClassName()
的
m_className= Util::toLower(className);
修改为:
m_className =className;
默认情况下,类名转换为了小写,但是小写后,到了authLoad函数时:
/src/runtime/base/builtin_functions.cpp +1958实现的:
Array params(ArrayInit(1,ArrayInit::vectorInit).set(className).create());
传参数,这里就传入了小写的了,但是实际我们需要的是原始的,可是在hhvm的Class和 ClassInfo类中都没有原始的类名了;
上面的m_className修改后,有几处还是有对m_className进行转小写操作的,我们可以来分析一下;
1) 这里起的是对比作用,所以无影响
类似这种的
Class_constant_expression.cpp:204(src\compiler\expression): hash_string(Util::toLower(m_className).c_str(), m_className.size());
2) 更新m_className
resolveStatic 函数:
voidStaticClassName::resolveStatic(const string &name) {
…..
m_className =Util::toLower(name);
}
ClassScopePtrStaticClassName::resolveClass() {
……..
} else if (m_parent) {
if (ClassScopePtr self =scope->getContainingClass()) {
if (!self->getOriginalParent().empty()){
m_className =Util::toLower(self->getOriginalParent());
……..
}
}
……
}
resolveStatic只有1个调用
resolveClass 是在存在基类时进行调用,但是即时更新了,也都是小写状态,对于查找什么的影响不大;
所以目前暂时用这种解决,以后有好的方法再进行研究;
87. Nginx proxy+rewrite到hhvm上 request_uri问题
Php代码:
$uri = $_SERVER['REQUEST_URI'];
echo $uri;
php url重写规则(nginx):
rewrite ^([^\.]*)/testuri\.html$ $1/index.php?mod=Testhzg&action=test5last;
proxy配置:
proxy_pass http://hhvms;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For$remote_addr;
正常情况下nginx + rewrite+fastcgi的输出结果:
testuri.html
而通过proxy到hhvm上的输出结果为:
index.php?mod=Testhzg&action=test5
显然php是rewrite后的结果,而hhvm是rewrite前的结果(就是原始路径)
如果要是想要hhvm+proxy也有这样的效果,那么可以这么搞:
Nginx中不进行rewrite,只进行proxy,然后由hhvm进行rewrite,然后就可以实现hhvm的request_uri也是rewrite后的结果了;
但是这样唯一的问题可能就是造成日志的问题了;
88. Cmake的gcc 版本问题解决
当使用cmake ..时
-- The C compiler identification is GNU4.4.6
-- The CXX compiler identification is GNU4.4.6
-- The ASM compiler identification is GNU
-- Found assembler: /usr/bin/cc
-- Check for working C compiler:/usr/bin/cc
-- Check for working C compiler:/usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working CXX compiler:/usr/bin/c++
-- Check for working CXX compiler:/usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- CMAKE_PREFIX_PATH was missing,proceeding anyway
-- Performing Test HAVE_GCC_46
-- Performing Test HAVE_GCC_46 – Failed
报了如上内容,是gcc版本低,这里提供了一条语句/usr/bin/cc
也就是这里判断版本是通过cc判断的,我安装了gcc 4.6.3然后在bin的目录下cp gcc cc
然后配置环境变量:
exportPATH=/export/files/gcc-4.6.3/bin:$PATH
就可以识别了,gcc-4.6.3/bin需要在前面,覆盖旧path中的cc路径
89. Hiphop libevent打补丁失败解决
git clonegit://github.com/libevent/libevent.git
cd libevent
git checkoutrelease-1.4.14b-stable
checkout有些问题,需要这么改:
git checkout –b 1.4.14b release-1.4.14b-stable
git checkout –b <branch> <tag>
cat../hiphop-php/hphp/third_party/libevent-1.4.14.fb-changes.diff | patch -p1
如果这样打包后还是有错误,打补丁失败,请查看服务器是否可以连接外网,我之前的问题是服务器不可以连接外网造成的
然后在可以上外网的机器上打好补丁copy过去,就可以直接编译用了
90. Libevent keepalive内存泄露问题解决
在libevent下的http.c中:
位置为2319行下面加入一行:
req->userdone= 1 ;
即可;
static void
evhttp_handle_request(struct evhttp_request*req, void *arg)
{
structevhttp *http = arg;
structevhttp_cb *cb = NULL;
event_debug(("%s:req->uri=%s", __func__, req->uri));
if(req->uri == NULL) {
event_debug(("%s:bad request", __func__));
if(req->evcon->state == EVCON_DISCONNECTED) {
/*liulei edit
solvekeepalive memery leak
huzhiguangadd note
*/
req->userdone = 1;
evhttp_connection_fail(req->evcon,EVCON_HTTP_EOF);
}else {
event_debug(("%s:sending error", __func__));
evhttp_send_error(req,HTTP_BADREQUEST, "Bad Request");
}
return;
}
91. Pcre问题
<?php
$pattern = '/^\/$/u' ;
$case = '' ;
$pathInfo = '/' ;
if(preg_match($pattern.$case,$pathInfo,$matches)){
echo "1111111111 $matches<br/>" ;
var_dump($matches) ;
} else {
echo "2222222222<br/>" ;
}
?>
当运行hhvm的时候,报了如下错误:
HipHop Warning: Compilation failed: thisversion of PCRE is compiled without UTF support at offset 0
这是由于编译pcre的时候没有添加支持utf-8的选项,在编译的时候加上该选项即可:
./configure --enable-utf
92. 直接应用bytecode
设置Authoritative为true
Repo {
Central {
Path = /export/servers/hhvm-1.1/repo/hhvm.hhbc.sq3
}
}
93. Libmemcached版本更新
更新hhvm的libmemcached版本:
默认的wiki版本是0.49:
更新1.0.5:
将include和lib一起cp到usr下,然后编译,编译好后,用:
Ldd hhvm|grep libmemcached
/export/dev_hhvm/usr/lib/libmemcached.so.9
是.9其实更新每个包下的libmemcached.so这个包到usr/lib下就可以;
更新1.0.17:
Include还是用1.0.5的,然后把1.0.17的libmemcached.so拷贝到/usr/lib下编译即可;
然后:
Ldd hhvm|grep libmemcached
/export/dev_hhvm/usr/lib/libmemcached.so.11
.11就是1.0.17的包了
94. Hhvm 1.0 删除扩展后扔会在ext_hhvm中的ext_hhvm_infotabs中生成解决方法
一般来说生成扩展需要执行以下几步:
sh generated_files.sh gen
sh generated_files.sh hhvm
sh generated_files.sh infotabs
当我们之前加过一个扩展,但是之后想删除,那么我删除了ext *.h和*.cpp,包括inc等等,但是最终还是会在ext_hhvm_infotabs.cpp中生成这些信息是为什么呢?
因为ext_hhvm_infotabs.cpp中的扩展的类信息等都是从idl/*.idl.php中获取的,那么你不清除该idl文件,那么这个符号表中就永远会生成你的扩展信息;
因为在gen_lib.php中的parseIDLForMethods类似这样的方法等都是去查找的idl文件
那么我们如果要彻底清除一个扩展就需要做到如下几步:
(1) 删除ext下的ext_xxx.h和ext_xxx.cpp,ext_xxx.ext_hhvm.cpp, ext_xxx.ext_hhvm.h
(2) 删除test下的内容test_ext_xxx.h 和test_ext_xxx.cpp
(3) 删除runtime/ext/profile下的extprofile_xxx.h
(4) 最后删除src/idl/xxx.idl.php
这样就完全删除该扩展了
95. Hhvm使用split 函数coredump问题解决方法
Split函数的测试脚本:
<?php
$date = "04/30/1973";
list($month, $day, $year) = split ('[/.-]', $date);
echo "Month: $month; Day: $day; Year: $year<br />\n";
?>
当多线程(并发)测试时,出现了coredump问题:
Coredump报的信息:
#0 node_new () at regparse.c:1105
#1 0x00007f54572a18a9 in node_new_cclass () at regparse.c:1130
#2 0x00007f54572a59a5 in parse_char_class (np=0x7f5445ce6b48, tok=0x7f5445ce6bf0, src=0x7f5445ce6c28, end=0x7f544c2f5c29 "", env=0x7f5445ce6e30) at regparse.c:4208
#3 0x00007f54572a6ea5 in parse_exp (np=0x7f5445ce6b48, tok=0x7f5445ce6bf0, term=<value optimized out>, src=0x7f5445ce6c28, end=0x7f544c2f5c29 "", env=0x7f5445ce6e30) at regparse.c:5268
#4 0x00007f54572a8110 in parse_branch (top=0x7f5445ce6ba8, tok=0x7f5445ce6bf0, term=0, src=0x7f5445ce6c28, end=0x7f544c2f5c29 "", env=0x7f5445ce6e30) at regparse.c:5433
#5 0x00007f54572a8234 in parse_subexp (top=0x7f5445ce6f28, tok=0x7f5445ce6bf0, term=0, src=0x7f5445ce6c28, end=0x7f544c2f5c29 "", env=0x7f5445ce6e30) at regparse.c:5470
#6 0x00007f54572a847a in parse_regexp (root=0x7f5445ce6f28, pattern=0x7f544c2f5c24 "[/.-]", end=0x7f544c2f5c29 "", reg=0x7f540c05c5a0, env=0x7f5445ce6e30) at regparse.c:5514
#7 onig_parse_make_tree (root=0x7f5445ce6f28, pattern=0x7f544c2f5c24 "[/.-]", end=0x7f544c2f5c29 "", reg=0x7f540c05c5a0, env=0x7f5445ce6e30) at regparse.c:5541
#8 0x00007f54572af2ab in onig_compile (reg=0x7f540c05c5a0, pattern=0x7f544c2f5c24 "[/.-]", pattern_end=<value optimized out>, einfo=0x0) at regcomp.c:5301
#9 0x00007f54572afbe3 in onig_new (reg=0x7f5445ce7040, pattern=0x7f544c2f5c24 "[/.-]", pattern_end=0x7f544c2f5c29 "", option=0, enc=0x7f54574fe320, syntax=0x2e2d660, einfo=0x0) at regcomp.c:5546
#10 0x00007f54572b7fb7 in regcomp (reg=0x7f5445ce7040, pattern=0x7f544c2f5c24 "[/.-]", posix_options=<value optimized out>) at regposix.c:154
#11 0x00000000010d559d in HPHP::php_split (spliton=..., str=..., count=-1, icase=false) at /export/dev_hhvm/hiphop-php_hzg/src/runtime/base/preg.cpp:1400
#12 0x00000000017b350a in HPHP::f_split (pattern=..., str=..., limit=-1) at /export/dev_hhvm/hiphop-php_hzg/src/runtime/ext/ext_preg.cpp:106
………………………….
最终发现是f_split函数出的问题,然后是调用了Oniguruma(正则库的问题);
问题出在了regparse.c:1105这里,由于这里默认采用的方式的线程原子操作,也就是没有对多进程进行处理,这里有一个链表是FreeNodeList是一个静态的变量,所以操作的时候就出现了争抢销毁,最终该对象成为了野指针;
那么如何解决这个问题呢?这里有一个宏默认是进行线程原子操作的,我们只要把这个宏注释掉就可以进行多线程或者多进程的操作了。
//#define USE_PARSE_TREE_NODE_RECYCLE
注释掉这个宏即可,然后我们重新编译Oniguruma;
由于最开始使用的是默认的yum 的库oniguruma-devel,这里我们需要去下载源码才可以;
安装完毕后,我们替换so即可;
该库的默认路径在:/usr/lib64/libonig.so.2
经过测试,改后无发现coredump问题;
http://www.geocities.jp/kosako3/oniguruma/
我用的版本是5.9.4
Latest release version 5.9.4 (2013/04/04) Change Log
5.9.3 (2012/10/26)
这个版本;
Git问题位置:
https://github.com/facebook/hiphop-php/issues/1111
96. hhvm 支持parse_str
测试脚本
<?php
//传入array
parse_str("id=23&name=John%20Adams",$a);
print_r($a);
echo var_dump($id);
echo "\n";
echo var_dump($name);
echo "\n";
//不传入array
parse_str("id=23&name=John%20Adams");
echo var_dump($id);
echo "\n";
echo var_dump($name);
echo "\n";
//传入array并且有同名变量
$name = 'Smith';
parse_str("id=23&name=John%20Adams", $a);
echo $name . "\n";
?>
提问:
https://github.com/facebook/hiphop-php/issues/1146
第一版修复地址:
https://github.com/facebook/hiphop-php/commit/c2ec3da9e74ed6d3fac7cded6ad29dc5b3947786
9月份该问题已经修复一部分,就是不传入参数的也可以捕获到:
parse_str("id=23&name=John%20Adams");
输出:
string(2) "23"
string(10) "John Adams"
但是如果是如上面代码的状况就会输出:
Array
(
[id] => 23
[name] => John Adams
)
HipHop Notice: Undefined variable: id in /export/data/www/test/test_ext/test_parse_str.php on line 7
NULL
HipHop Notice: Undefined variable: name in /export/data/www/test/test_ext/test_parse_str.php on line 9
NULL
完全修复无diff的代码为ext_string.cpp中:
void f_parse_str(CStrRef str, VRefParam arr /* = null */) {
Variant result;
HttpProtocol::DecodeParameters(result, str.data(), str.size());
if(!arr.isReferenced()) {
f_extract(result.toArray());
return;
}
///////////////////////////////防止出现Notice也就是变量未定义//////////////////////////
Array vars=result.toArray();
Array newVars=Array::Create();
Array allVars=f_get_defined_vars();
for (ArrayIter iter(vars); iter; ++iter) {
Variant key = iter.first();
if(!allVars.exists(key)){
Variant value;
value.setNull();
newVars.set(key,Variant(value));
}
}
f_extract(newVars);
arr = result.toArray();
///////////////////////////////////////////////////////////////////////////////
}
这样修改后和php无diff
如果是旧版本的,需要加入一个头:
#include "hphp/runtime/ext/ext_variable.h"
因为f_extract 是在该头文件中的函数
========================================================================
下面的是正确的修复,上面虽然内容一致,但是其实最终实现语法和zend不同了,主要是变量存在问题;
其实和php语法一致的还是后来官方修复后的内容:
我上面改的内容其实避免了notice,但是最终当传入$a后,这个变量应该是不存在的;
https://github.com/facebook/hiphop-php/issues/1146
见:
@huzhiguang, compare output of this script on PHP and your patched HHVM:
<?php
parse_str("id=23&name=John%20Adams",$a);
var_dump(isset($name));
PHP Output:
bool(false)
As I said before, this is because no variables should be extracted when second parameter of parse_str is given. Seehttps://github.com/php/php-src/blob/master/ext/standard/string.c#L4454-4460 for details.
在php的代码实现中:
https://github.com/php/php-src/blob/master/ext/standard/string.c#L4454-4460
if (arrayArg == NULL) {
zval tmp;
if (!EG(active_symbol_table)) {
zend_rebuild_symbol_table(TSRMLS_C);
}
Z_ARRVAL(tmp) = EG(active_symbol_table);
sapi_module.treat_data(PARSE_STRING, res, &tmp TSRMLS_CC);
} else {
zval ret;
array_init(&ret);
sapi_module.treat_data(PARSE_STRING, res, &ret TSRMLS_CC);
/* Clear out the array that was passed in. */
zval_dtor(arrayArg);
ZVAL_COPY_VALUE(arrayArg, &ret);
}
当array存在的时候也就是else分支是不进行创建变量的;
所以官方提供的代码最终实现是正确的:
最终实现:
void f_parse_str(CStrRef str, VRefParam arr /* = null */) {
Variant result;
HttpProtocol::DecodeParameters(result, str.data(), str.size());
if(!arr.isReferenced()) {
f_extract(result.toArray());
return;
}
arr = result.toArray();
}
97. 将变量加入到符号表的函数f_extract
Php的extract函数是将一个array的内容添加到vm的变量中,让其变量能够找到;
如:
$a=array(“test”=>”1”,”test1”=>”2”);
extract($a);
echo $test;
输出是1,也就是这时候就注册了2个变量test,test1;