Lua中的环境表
概念
lua 将所有的全局变量都存在于一个常规的 table 中,这个 table 称为环境表或简称为环境。(lua 会提供一个全局环境表_G)。默认情况下,每个函数的环境都是_G,因此该函数中的所有全局变量都将从_G中查找。当一个函数被创建时,它将从创建它的函数中继承环境。我们可以使用getfenv(f)
来获取当前函数的环境,也可以通过setfevn(f, table)
来更改当前函数环境。
getfenv(f)
可以用来获取某一函数的环境,参数f
可以是一个函数还可以是一个栈层级。f
设为0会得到_G,设为1会得到当前调用getfenv(f)
的函数环境,设为2会得到调用当前函数的函数环境,以此类推......
setfenv(f, table)
可以用来为某一函数设置一个新的环境。参数f
为0会更改当前运行线程的环境;设为1会更改当前函数的环境;设为2会更改调用当前函数的函数环境,以此类推......
实践
了解基本原理之后,我们就可以利用环境来搞点事情。比如:我们可以 hook lua 中所有全局变量的访问与设置,实现如下。
function change_enviroment()
local new_env = {}
local new_env_meta = {
__index = function(table, key)
--调用change_enviroment的函数中,所有对全局变量的访问操作都会执行到这里
end,
__newindex = function(table, key, value)
--调用change_enviroment的函数中,所有设置全局变量的操作都会执行到这里
end
}
setmetatable(new_env, new_env_meta)
setfenv(2, new_env) --设置调用change_enviroment的函数环境为new_env
end
--设置下环境,此后,所有全局变量的相关操作都会被hook
change_enviroment()
--会执行到__index中
print("xxx")
--由于是设置一个全局函数,所以会执行到__newindex中
function myFunction()
end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
上述例子,我们就可以很轻易地从 lua 通信到原生中,进而可以搞一些事情,比如 hotfix。