private function _importClassMap(
        $strictImportClassName)
    {
        // Begin via reflection to resolve the EXACT name of the class they want
        // to import, so that we can trust its name completely.
        try {
            // NOTE: The strict, global "\"-name is necessary here, to guarantee
            // that we find the correct target class via the global namespace.
            $reflector = new ReflectionClass($strictImportClassName);
            $importClassName = $reflector->getName(); // The clean, real name.
            $strictImportClassName = Utilities::createStrictClassPath($importClassName);
        } catch (ReflectionException $e) {
            // This should never be able to fail (since our caller already
            // verified that the class exists), but treat failure as a bad map.
            throw new BadPropertyMapException(sprintf(
                'Reflection failed for class "%s", when trying to import it into class "%s". Reason: "%s".',
                $strictImportClassName, $this->_currentClassInfo['strictClassName'], $e->getMessage()
            ));
        }

        // FATAL: If the encountered import-statement literally refers to itself
        // (the class we're currently compiling in the hierarchy), then it's a
        // totally ridiculous circular self-reference of the most insane kind.
        if ($importClassName === $this->_currentClassInfo['className']) {
            throw new CircularPropertyMapException(
                $strictImportClassName,
                $strictImportClassName
            );
        }

        // FATAL: If the import-statement refers to ANY class in OUR OWN
        // current class' hierarchy, then it's a circular self-reference. We
        // forbid those because they make ZERO sense. For example: "ABCD", in
        // that case, "D" COULD definitely import "B" because "D" is later in
        // the chain and "B" is therefore already resolved. But WHY? We already
        // inherit from it! And we could NEVER do the reverse; "B" could never
        // import "D", because "D" depends on "B" being fully compiled already.
        // Likewise, we can't allow stupid things like "B imports B". Doesn't
        // make sense. Therefore, we disallow ALL self-imports.
        //
        // NOTE: In the example of "B" importing "D", that's NOT caught here
        // since the classname "D" wouldn't be part of B's hierarchy. But it
        // will be caught during our upcoming attempt to sub-compile "D" to
        // parse ITS hierarchy, since "D" will begin to compile and check its
        // own class hierarchy, and will arrive at the "B" class and will then
        // detect that "B" is locked as "already being resolved", since the
        // ongoing resolving of "B" was what triggered the compilation of "D".
        if (isset($this->_classHierarchy[$importClassName])) {
            // NOTE: strictSolveClassName goes in "arg1" because we're the ones
            // trying to import an invalid target class that's already part of
            // our own hierarchy.
            throw new CircularPropertyMapException(
                $this->_strictSolveClassName,
                $strictImportClassName
            );
        }

        // FATAL: Also prevent users from importing any class that's in the list
        // of "locked and currently being resolved", since that means that the
        // class they're trying to import is ITSELF part of a compilation-chain
        // that's CURRENTLY trying to resolve itself right now.
        //
        // NOTE: This catches scenarios where class-chains have common ancestors
        // but then diverge and go into a circular reference to each other. For
        // example, "A extends LazyJsonMapper, imports B", "B extends
        // LazyJsonMapper, imports A". Imagine that you construct "A", which
        // locks "A" during its compilation process. The parent "LazyJsonMapper"
        // class is successfully compiled since it has no dependencies. Then "A"
        // sees "import B" and sub-compiles B. (Remember that "A" remains locked
        // when that happens, since "A" is waiting for "B" to resolve itself.)
        // The compilation code of "B" begins running. It first checks its
        // inheritance hierarchy and sees nothing locked (LazyJsonMapper is
        // unlocked because it's already done, and B is unlocked because B has
        // not locked itself yet). Next, "B" sees an "import A" statement. It
        // succeeds the "block import of A if it's part of our own hierarchy"
        // check above, since B is NOT "extended from A".
        //
        // So then we're at a crossroads... there IS a circular reference, but
        // we don't know it yet. We COULD let it proceed to "resolve A by
        // sub-compiling the map for A", which would give us a call-stack of
        // "compile A -> compile B -> compile A", but then the 2nd "A" compiler
        // would run, and would do its early lock-check and notice that itself
        // (A) is locked, since the initial compilation of "A" is not yet done.
        // It would then throw a non-sensical error saying that there's a
        // circular reference between "A and A", which is technically true, but
        // makes no sense. That's because we waited too long!
        //
        // So, what the code BELOW does instead, is that when "B" is trying to
        // resolve itself (during the "compile A -> import B -> compile B"
        // phase), the "B" compiler will come across its "import A" statement,
        // and will now detect that "A" is already locked, and therefore throws
        // a proper exception now instead of letting "A" attempt to compile
        // itself a second time as described above. The result of this early
        // sanity-check is a better exception message (correct class names).
        foreach ($this->_propertyMapCache->compilerLocks as $lockedClassName => $isLocked) {
            if ($isLocked && $lockedClassName === $importClassName) {
                // NOTE: strictSolveClassName goes in "arg2" because we're
                // trying to import something unresolved that's therefore higher
                // than us in the call-stack.
                throw new CircularPropertyMapException(
                    $strictImportClassName,
                    $this->_strictSolveClassName
                );
            }
        }

        // Now check if the target class is missing from our cache, and if so
        // then we must attempt to compile (and cache) the map of the target
        // class that we have been told to import.
        //
        // NOTE: This sub-compilation will perform the necessary recursive
        // compilation and validation of the import's WHOLE map hierarchy. When
        // the compiler runs, it will ensure that nothing in the target class
        // hierarchy is currently locked (that would be a circular reference),
        // and then it will lock its own hierarchy too until it has resolved
        // itself. This will go on recursively if necessary, until ALL parents
        // and ALL further imports have been resolved. And if there are ANY
        // circular reference ANYWHERE, or ANY other problems with its
        // map/definitions, then the sub-compilation(s) will throw appropriate
        // exceptions.
        //
        // We won't catch them; we'll just let them bubble up to abort the
        // entire chain of compilation, since a single error anywhere in the
        // whole chain means that whatever root-level compile-call initially
        // began this compilation process _cannot_ be resolved either. So we'll
        // let the error bubble up all the way to the original call.
        if (!isset($this->_propertyMapCache->classMaps[$importClassName])) {
            // Compile the target class to import.
            // NOTE: We will not catch the error. So if the import fails to
            // compile, it'll simply output its own message saying that
            // something was wrong in THAT class. We don't bother including any
            // info about our class (the one which imported it). That's still
            // very clear in this case, since the top-level class compiler and
            // its hierarchy will be in the stack trace as well as always having
            // a clearly visible import-command in their class property map.
            $this->_subcompile($importClassName); // Throws.
        }

        // Now simply loop through the compiled property map of the imported
        // class... and add every property to our own compiled property map. In
        // case of clashes, we use the imported one.
        // NOTE: We'll directly assign its PD objects as-is, which will assign
        // the objects by shallow "shared instance", so that we re-use the
        // PropertyDefinition object instances from the compiled class that
        // we're importing. That will save memory.
        // NOTE: There's no point doing an equals() clash-check here, since
        // we're importing an EXISTING, necessary definition from another class,
        // so we won't save any memory by avoiding their version even if the
        // definitions are equal.
        foreach ($this->_propertyMapCache->classMaps[$importClassName] as $importedPropName => $importedPropDefObj) {
            $this->_currentClassPropertyMap[$importedPropName] = $importedPropDefObj;
        }
    }