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()
            ));
        }
    }
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()
            ));
        }
    }
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 ( ) ) ) ; } }
Compile a property definition string and add it to the current class.

Attempts to compile the definition, and then appends it to the current
class' final compiled map, IF the definition is valid and describes a
new/different value compared to what's already in the current class map.

@param string $propName   The property name.
@param string $propDefStr A string describing the property.

@throws BadPropertyDefinitionException
Compile a property definition string and add it to the current class .