What does ``getfenv()`` do?

I found scripts using getfenv and it’s very interesting on they use them. I tried all my ways to know how it works, but some resources appears to be confusing as told. What does it do? How do you use it in some ways?

10 Likes

getfenv is used to get the current environment of a function. It returns a table of all the things that function has access to. You can also set the environment of a function to another environment.

7 Likes

Forgot to include examples of where this could be used. Although not very common uses, there are some. In the past Script Builders used getfenv to get the environment of a script, and setfenv to set the environment of a created script’s environment to a fake environment, so they couldn’t affect the real one. They could also inject custom global functions.

Not entirely sure if this uses getfenv or setfenv, but the use in Crazyman32’s AeroGameFramework is making the environment of each module have access to other modules without having to require them, and having access to remotes without having to directly reference them.

7 Likes

EDIT 10/22/2022: Despite being marked, this is not the solution, this is a clarification to a misconception. Please see kiriot22’s post below for the real solution:


Aero doesn’t use function environments. Each module returns a table, which is wrapped with a metatable contained in the Aero internal set up script.

Relevant code highlights (obviously review the file itself as that’s a better reference):

local AeroServer = {
	Services = {};
	Modules  = {};
	Shared   = {};
}

local mt = {__index = AeroServer}

function AeroServer:WrapModule(tbl)
	assert(type(tbl) == "table", "Expected table for argument")
	tbl._events = {}
	setmetatable(tbl, mt)
	if (type(tbl.Init) == "function" and not tbl.__aeroPreventInit) then
		tbl:Init()
	end
	if (type(tbl.Start) == "function" and not tbl.__aeroPreventStart) then
		FastSpawn(tbl.Start, tbl)
	end
end


-- Setup table to load modules on demand:
function LazyLoadSetup(tbl, folder)
	setmetatable(tbl, {
		__index = function(t, i)
			local obj = require(folder[i])
			if (type(obj) == "table") then
				AeroServer:WrapModule(obj)
			end
			rawset(t, i, obj)
			return obj
		end;
	})
end

On the other hand, SyncAdmin is a good example of a use of function environments. One of its developers did reply to an old resource thread I made, delving into the application of get/setfenv a bit:

18 Likes

Yeah I wasn’t entirely sure if Aero used getfenv and setfenv, or not. I was on mobile and didn’t have the chance to check. But these were the only examples I could think off the top of my head that you can use the functions for.

4 Likes

As others have said, getfenv() returns the environment of your script (“env” for short). But what is an env?

You probably know that each script has a script variable by default. It’s a global variable (the one created without using local, i.e. foo = "bar").
But global variables have to be stored somewhere, right? The answer is yes - they are stored within a dictionary table assigned to each script when it runs. That table is called the script’s env.

So if that table stores your global variables and using getfenv() let’s you access it, it means you can do something like this:

foo = "bar"
print(getfenv().foo) --> bar

(although you probably won’t ever do that since you should rather use local over global variables)

Now, remember when I said the env is assigned to your script? Well, it’s also assigned to every function you create in your script! And that brings us to an argument getfenv can take: a function.
Doing getfenv(func) where func is a function, will return the env assigned to it (unless it’s a function created by roblox, like print or FindFirstChild, in which case it will return your own env).

Now the more complex part: getfenv can also take a number as an argument. But how does that work?
Basically, it will return the env of the function in an order they were called, starting from 1, meaning

  • getfenv(1) will return the env of the current function (this is same as doing getfenv(), basically)
  • getfenv(2) will return the env of the function that called the current function
  • getfenv(3) will return the env of the function that called the function which called the current function

and so on.
You can also use getfenv(0), which will return the global env, or as someone said “the normal one, all the way at the top”.

130 Likes

This is a really good explanation! Thanks for putting more information into it, and giving examples :grinning:

4 Likes

Thank you for explaining this. I would have never known exactly how to use getfenv() without you! :smiley:
Edit: Sorry for the unnecessary bump. I’m new to the forums, and I didn’t know this would bump the post.

3 Likes

Thanks - I’ve been using setfenv in my admin system to create easy-to-use plugins. I was confused for the longest time, but thank you for the input!