The reason the end code can't make references to the arguments passed to the start code is that they are expanded separately. That is, if you have an environment myenv taking one argument and you write
\begin{myenv}{myarg}
some text...
\end{myenv}
then LaTeX expands \begin{myenv}, passing it the single argument myarg, and pastes the result in front of "some text...". The document then proceeds as it will, with other environments possibly opening and closing (perhaps even other instances of myenv) before \end{myenv} is finally reached. When that happens, it gets expanded, but there is no way of knowing anymore what the argument to the original \begin{myenv} was. Thus, there is no way of passing it to the end code unless you chose to save its value.
It's worth examining why this is confusing compared to \newcommand. Both appear to work in the same way:
\newcommand{\mymacro}[1]{macro code with #1}
\newenvironment{myenv}[1]{start code with #1}{end code}
The difference is that a macro is a single thing, which is reflected in the notation: you write \mymacro with a backslash but myenv without, perhaps signifying that it is a higher-level abstraction. Indeed, \newenvironment creates a pair of macros \myenv and \endmyenv which function as described above.
The setup is designed to create the appearance of "blocking off" the document into chunks contained in various environments, but in fact, the unity of each environment is a bit illusory. LaTeX keeps track of the name of the environment it most recently entered, but at no time (barring clever tricks) does it ever "see" the entire environment at once, either forward (when starting) nor backwards (when ending).
xparsepackage, you have\NewDocumentEnvironmentwhere it's possible to refer to the arguments also in the closing code. – egreg Apr 30 '11 at 19:59\NewDocumentEnvironmentcause the start code to create a unique macro name, known to the end code, storing the arguments? Or does it look ahead? Some kind of call stack, perhaps? – Ryan Reich Apr 30 '11 at 20:06\envargswhich gets filled each time an environment is called with arguments? So then TeX itself takes care of the "call stack" by saving and restoring its value when passing through nested environments. – Ryan Reich Apr 30 '11 at 20:44xparsenot mentioned in any answer? it seems the right way to solve the problem. – Nicola Gigante Dec 06 '17 at 12:06xparseas a good solution. – Alan Munn Dec 06 '17 at 14:01