Rearranging the order of setting keys internally (from a user key-value list) will be expensive. Setting the list twice may make the order of the list less relevant, but the key author has to exercise some caution.
Let us assume the following keys.
\mp@a depends on \mp@b that comes later, so we have to make the evaluation of \mp@a conditional on knowing \mp@b:
\define@key{fam}{a}[1cm]{%
\ifdefined\mp@b\edef\mp@a{\the\dimexpr#1+\mp@b}\fi
}
\define@key{fam}{b}[.5cm]{\def\mp@b{#1}}
The updated value of \mp@a will not be known until key b has been set.
Setting the list twice will make the order of the list less relevant. This can be achieved via the following
\newcount\setkeyscount
\def\setkeystwice{\@testopt\s@tkeystwice{KV}}
\def\s@tkeystwice[#1]#2#3{%
\setkeyscount\z@
\loop
\setkeys[#1]{#2}{#3}%
\advance\setkeyscount\@ne
\ifnum\setkeyscount<\tw@
\repeat
}
\setkeystwice{a=1cm,b=2cm}
Here is a more formal approach, which requires no special conditionals in defining the keys. The key author only needs to call \orderofkeys with the right order of how he wants the keys to be set internally. Note that (i) \orderofkeys (actually, \XKV@setheadkeys) does not filter out 'current keys' (i.e., keys appearing in the user-supplied key-value list) from its preset list; and (ii) \orderofkeys takes a key-value list but the user can omit values for keys with default values.
\documentclass{article}
\usepackage{xkeyval}
\makeatletter
\newcommand*\headkeys{\XKV@stfalse\XKV@testoptb\XKV@headkeys}
\def\XKV@headkeys#1{\XKV@pr@setkeys{#1}{headkeys}}
\let\orderofkeys\headkeys
% \setkeystwice[<pref>]{<fam>}[<na>]{<kvlist>}
\def\setkeystwice{\XKV@testopta{\XKV@testoptc\XKV@setkeystwice}}
\def\XKV@setkeystwice[#1]#2{%
\ifnum\XKV@depth=\z@\let\XKV@rm\@empty\fi
\XKV@checksanitizea{#2}\XKV@tempb
\let\XKV@naa\@empty
\XKV@for@o\XKV@tempb\XKV@tempa{%
\expandafter\XKV@g@tkeyname\XKV@tempa=\@nil\XKV@tempa
\XKV@addtolist@x\XKV@naa\XKV@tempa
}%
\expandafter\XKV@s@tkeystwice\expandafter{\XKV@tempb}{#1}%
}
\def\XKV@s@tkeystwice#1#2{%
\XKV@setheadkeys{#2}%
% Set the usual xkeyval's head keys:
\XKV@usepresetkeys{#2}{preseth}%
\XKV@s@tkeys{#1}{#2}%
\XKV@s@tkeys{#1}{#2}%
% Set the usual xkeyval's tail keys:
\XKV@usepresetkeys{#2}{presett}%
\let\CurrentOption\@empty
}
% Unlike xkeyval package's \XKV@usepresetkeys, \XKV@setheadkeys instantiates
% head/ordered keys whether or not they appear in the current (user-supplied) key-value
% list.
\def\XKV@setheadkeys#1{%
\XKV@presettrue
\XKV@for@eo\XKV@fams\XKV@tfam{%
\XKV@makehd\XKV@tfam
\XKV@ifundefined{XKV@\XKV@header headkeys}{}{%
\XKV@toks\expandafter\expandafter\expandafter
{\csname XKV@\XKV@header headkeys\endcsname}%
\@expandtwoargs\XKV@s@tkeys{\the\XKV@toks}{#1}%
}%
}%
\XKV@presetfalse
}
% Example use:
% We could have used command-keys to define these keys, but never mind:
\define@key{box}{boxwidth}[1cm]{\def\boxwidth{#1}}
\define@key{box}{boxheight}[.5cm]{\def\boxheight{#1}}
\define@key{box}{framecolor}[black]{\def\framecolor{#1}}
\define@key{box}{shadecolor}[white]{\def\shadecolor{#1}}
\define@key{box}{shadowcolor}[gray]{\def\shadowcolor{#1}}
\define@key{box}{framesize}[.4pt]{\def\framesize{#1}}
\define@key{box}{boxsep}[5mm]{\def\boxsep{#1}}
% Note: \shadowsize is a fraction of \boxwidth plus \boxheight. [The ratio is given by
% the key 'shadowratio'.] Hence 'boxwidth' and 'boxheight' must be set before
% 'shadowratio'. We want to allow the user to set the keys in any order.
\define@key{box}{shadowratio}[.25]{%
\def\tempa##1.##2\@nil{##1}%
\edef\tempa{\expandafter\tempa\the\dimexpr#1pt*100\relax\@nil}%
\edef\shadowsize{\the\dimexpr(\boxwidth+\boxheight)/\tempa}%
}
% Since the values of 'boxwidth' and 'boxheight' are needed when setting 'shadowratio',
% we preset/order 'boxwidth' and 'boxheight' before 'shadowratio'. The user could then
% set the keys in any order he likes.
\orderofkeys{box}{boxwidth,boxheight,shadowratio,framecolor,shadecolor,
shadowcolor,framesize,boxsep}
% Let us define a sample method that uses these keys and \setkeystwice:
\usepackage{xcolor}
\newcommand*\somebox[2][]{%
\setkeystwice{box}{#1}%
\begingroup
\fboxrule=\framesize\relax
\setbox0=\hbox{%
\fcolorbox{\framecolor}{\shadecolor}{%
\vbox to \boxheight{\vfil\hbox to\boxwidth{\hfil{#2}\hfil}\vfil}%
}%
}%
\hskip\shadowsize\hskip\boxsep
\color{\shadowcolor}%
\rule[-\dp0]{\wd0}{\the\dimexpr\ht0+\dp0\relax}%
\llap{\raisebox{\shadowsize}{\box0\hskip\shadowsize}}%
\endgroup
}
\makeatother
\begin{document}
% Now the user may set the keys in any order he wishes.
\somebox[boxwidth=1cm,boxheight=.5cm,shadowratio=.25,framesize=1pt]{box 1}
\somebox[boxwidth=2cm,boxheight=1cm,shadowratio=.1,
framesize=2pt,framecolor=green,shadowcolor=blue]{box 2}
\end{document}