private function _processPropertyDefinitionString(
        $propName,
        $propDefStr)
    {
        try {
            // Validates the definition and throws if bad.
            // NOTE: The namespace argument here is INCREDIBLY important. It's
            // what allows each class to refer to classes relative to its own
            // namespace, rather than needing to type the full, global class
            // path. Without that parameter, the PropertyDefinition would only
            // search in the global namespace.
            // NOTE: "use" statements are ignored since PHP has no mechanism
            // for inspecting those. But the user will quickly notice such a
            // problem, since such classnames will warn as "not found" here.
            $propDefObj = new PropertyDefinition( // Throws.
                $propDefStr,
                $this->_currentClassInfo['namespace']
            );

            // MEMORY OPTIMIZATION TRICK: If we wanted to be "naive", we could
            // simply assign this new PropertyDefinition directly to our current
            // class property map, regardless of whether the property-name key
            // already exists. It would certainly give us the "right" result...
            //
            // But imagine if one of our parent objects or previous imports have
            // already created a property as "foo":"string[]", and imagine that
            // we ALSO define a "foo":"string[]", even though we've already
            // inherited that EXACT compiled instruction. What would happen?
            //
            // Well, if we instantly assign our own, newly created object, even
            // though it's equal to an identically named and identically defined
            // property that we've already inherited/imported, then we waste RAM
            // since we've now got two INDEPENDENT "compiled property" object
            // instances that describe the EXACT same property-settings.
            //
            // Therefore, we can save RAM by first checking if the property name
            // already exists in our currently compiled map; and if so, whether
            // its pre-existing PropertyDefinition already describes the EXACT
            // same settings. If so, we can keep the existing object (which we
            // KNOW is owned by a parent/import and will therefore always remain
            // in memory). Thus saving us the RAM-size of a PropertyDefinition
            // object. In fact, the re-use means the RAM is the same as if the
            // sub-class hadn't even overwritten the inherited/imported property
            // AT ALL! So this protective algorithm makes class JSON property
            // re-definitions to identical settings a ZERO-cost act.
            //
            // IMPORTANT: This only works because compiled properties are
            // immutable, meaning we can trust that the borrowed object will
            // remain the same. We are NEVER going to allow any runtime
            // modifications of the compiled maps. So re-use is totally ok.
            if (!isset($this->_currentClassPropertyMap[$propName])
                || !$propDefObj->equals($this->_currentClassPropertyMap[$propName])) {
                // Add the unique (new/different) property to our class map.
                $this->_currentClassPropertyMap[$propName] = $propDefObj;

                // Alright, we've encountered a brand new property, and we know
                // it's pointing at a LazyJsonMapper if it's an object. But we
                // DON'T know if the TARGET class map can actually COMPILE. We
                // therefore need to add the class to the list of encountered
                // property classes. But only if we haven't already compiled it.
                if ($propDefObj->isObjectType
                    && !isset($this->_propertyMapCache->classMaps[$propDefObj->propType])) {
                    // NOTE: During early compilations, at the startup of a PHP
                    // runtime, this will pretty much always add classes it sees
                    // since NOTHING is compiled while the first class is being
                    // compiled. Which means that this list will contain classes
                    // that are currently BEING SOLVED as the class hierarchy
                    // keeps resolving/compiling itself. But we'll take care of
                    // that by double-checking the list later before we're done.
                    // TODO: PERHAPS we can safely optimize this HERE by also
                    // checking for the target class in _propertyMapCache's list
                    // of locked classes... But planning would be necessary.
                    $this->uncompiledPropertyClasses[$propDefObj->propType] = true;
                }
            }
        } catch (BadPropertyDefinitionException $e) {
            // Add details and throw from here instead.
            throw new BadPropertyDefinitionException(sprintf(
                'Bad property definition for "%s" in class "%s" (Error: "%s").',
                $propName, $this->_currentClassInfo['strictClassName'], $e->getMessage()
            ));
        }
    }