Phoenix框架中__using__/1宏的用途、示例及apply调用解析
__using__/1 Macro in Phoenix's *_web.ex File Great question! Let's break down what this macro does, show it in action, and clarify where that apply call targets.
What's the Purpose of __using__/1?
This macro acts as a centralized dispatch hub for Phoenix's code injection system. When you write use YourAppWeb, :controller (or :view, :channel, etc.) in a module, it triggers this macro. Instead of writing repetitive import/use statements in every controller/view/channel, Phoenix lets you define all that shared setup in your *_web.ex file, and this macro routes your use call to the right setup function.
It keeps your code DRY (Don't Repeat Yourself) by consolidating all the common boilerplate for different Phoenix component types in one place.
Practical Example in Action
Let's walk through how this works with a real-world scenario.
First, look at the helper functions defined in your YourAppWeb module (right above the __using__/1 macro in lib/your_app_web.ex):
# Example controller setup function in YourAppWeb def controller do quote do # Bring in core Phoenix Controller functionality use Phoenix.Controller, formats: [:html, :json], layouts: [html: YourAppWeb.Layouts] # Import common utilities import Plug.Conn import YourAppWeb.Gettext alias YourAppWeb.Router.Helpers, as: Routes end end # Example view setup function def view do quote do use Phoenix.View, root: "lib/your_app_web/templates", namespace: YourAppWeb # Import shared view helpers import YourAppWeb.ErrorHelpers import YourAppWeb.Gettext alias YourAppWeb.Router.Helpers, as: Routes end end
Now, when you create a controller, you just need one line to pull in all that setup:
defmodule YourAppWeb.UserController do # This triggers __using__/1 with :controller as the argument use YourAppWeb, :controller def index(conn, _params) do users = YourApp.Accounts.list_users() # We can use render/3 directly because it's imported via the controller setup render(conn, :index, users: users) # Routes is also available without manual aliasing end end
Same goes for a view module:
defmodule YourAppWeb.UserView do use YourAppWeb, :view # Now we have access to Phoenix.View functions, ErrorHelpers, and Routes automatically end
Where Does the apply Call Target?
The line apply(__MODULE__, which, []) is straightforward once you parse it:
__MODULE__refers to the current module (e.g.,YourAppWeborChatWeb—the module where the__using__/1macro is defined)whichis the atom you passed touse(like:controlleror:view)- So
applycalls the function with the same name as thewhichatom in theYourAppWebmodule. For example, if you pass:controller, it callsYourAppWeb.controller(), which returns the quoted code that gets injected into your module.
These target functions (controller/0, view/0, channel/0, etc.) are always defined in the same *_web.ex file as the __using__/1 macro—Phoenix generates them automatically when you create a new project, and you can customize them to add your own shared imports/aliases.
内容的提问来源于stack exchange,提问作者nelsonic

