Re: Storing data structires in DB

From: Date: Fri, 01 Apr 2005 17:49:55 +0000
Subject: Re: Storing data structires in DB
References: 1  Groups: php.general 
Request: Send a blank email to php-general+get-212044@lists.php.net to get a copy of this message
Ok, I wrote something that fits my needs. But, as I said, it is slow. Too slow. Is anyone except me interested in human-editable serialize? Can anyone help me with optimization? And please do not tell me that I need to write it in C++. The thing should be portable. ========================== define('CMS_ARR_BEGIN', 1); define('CMS_ARR_END', 2); define('CMS_COMA', 3); define('CMS_ARROW', 4); define('CMS_SCALAR', 5); function encode($var) { if (is_array($var)) {
       $code = '(';
       foreach ($var as $key => $value) {
           $code .= encode($key).'='.encode($value).',';
       }
       $code = chop($code, ','); //remove unnecessary coma
       $code .= ')';
       return $code;
} else {
       if (is_string($var)) {
           if (strpos($var, "'") !== FALSE) {
               $var = str_replace("'", "''", $var);
           }
           return "'".$var."'";
       } elseif (is_numeric($var)) {
           return $var;
       } elseif (is_bool($var)) {
           return ($var ? 'T' : 'F');
       } else {
           return 'N';
       }
} } function decode($str){
    $stack = array();
    $scalars = array();
    $strLen = strlen($str);
    while ($ptr < $strLen) {
        $ptrChar = $str{$ptr};
        if (preg_match('/\s/', $ptrChar )) {
            //do nothing
        } else {
            if ($ptrChar == '(') {
                $stack[] = CMS_ARR_BEGIN;
            } elseif ($ptrChar == ')') {
                $arrBegins = array_pop(array_keys($stack, CMS_ARR_BEGIN));
                if ($arrBegins === FALSE) {
                    user_error("Unexpected ')'", E_USER_WARNING);
                    return;
                }
                $arrTokens = array_splice($stack, $arrBegins + 1); //get array content
                array_pop($stack); //remove beginning token
                if (empty($arrTokens)) { //empty array
                    $scalars[] =  array();
                    $stack[] = CMS_SCALAR;
                    continue;
                }
                $arrScalars = array();
                foreach ($arrTokens as $token) {
                    if ($token == CMS_SCALAR) {
                        $arrScalars[] = array_pop($scalars); /*arrScalars are now reversed, so first token is the last scalar*/
                    }
                }
                if ($arrTokens[sizeof($arrTokens) - 1] != CMS_COMMA) {//for symmetry
                    array_push($arrTokens, CMS_COMMA);
                }
                $arrBuffer = array();
                reset($arrTokens);
                while (list(, $token) = each($arrTokens)) {
                    if ($token == CMS_SCALAR) {
                        list(,$nextTok) = each($arrTokens);
                        if ($nextTok == CMS_COMMA) {
                            $arrBuffer[] = array_pop($arrScalars);
                            continue;
                        } elseif ($nextTok == CMS_ARROW) {
                            list(, $valTok) = each($arrTokens);
                            if ($valTok != CMS_SCALAR) {
                                var_dump($arrTokens);
                                var_dump($arrScalars);
                                user_error("Invalid token encountered during array compression: $valKey =>  $valTok", E_USER_WARNING);
                                return;
                            }
                            $arrBuffer[array_pop($arrScalars)] = array_pop($arrScalars);
                            list($valKey, $valTok) = each($arrTokens);
                            if ($valTok != CMS_COMMA) {
                                var_dump($arrTokens);
                                var_dump($arrScalars);
                                user_error("Invalid token encountered during array compression: $valKey =>  $valTok", E_USER_WARNING);
                                return;
                            }
                        } else {
                            echo "Array compression dump:\n";
                            var_dump($arrTokens);
                            var_dump($arrScalars);
                            user_error("Invalid token encountered during array compression:$ntk => $nextTok", E_USER_WARNING);
                            return;
                        }
                    } else {
                        echo "Array compression dump:\n";
                        var_dump($arrTokens);
                        var_dump($arrScalars);
                        user_error("Invalid token encountered during array compression:$key => $token", E_USER_WARNING);
                        return;
                    }
                }
                $scalars[] = $arrBuffer; //now multiple scalars replaced with array itself
                $stack[] = CMS_SCALAR;
            } elseif (preg_match('/["\']/', $ptrChar)) {
                $qEnd = strpos($str, $ptrChar, $ptr + 1);
                while ($str{$qEnd + 1} == $str{$qEnd}) { //deal with escapes
                    $qEnd = strpos($str, $ptrChar, $qEnd + 2);
                }
                if ($qEnd === FALSE) {
                    user_error("String is not terminated", E_USER_WARNING);
                    return NULL;
                }
                $stack[] = CMS_SCALAR;
                $scalars[] = str_replace($ptrChar.$ptrChar, $ptrChar, substr($str, $ptr + 1, $qEnd - ($ptr+1)));
                $ptr = $qEnd;
            //} elseif (in_array($ptrChar, $numerics)) {
            } elseif (preg_match('/^[0-9\+\-]$/', $ptrChar)) {
                $numEndComma = strpos($str, ',', $ptr);
                $numEndArrow = strpos($str, '=', $ptr);
                if ($numEndComma === FALSE) { $numEndComma = $strLen; }
                if ($numEndArrow === FALSE) { $numEndArrow = $strLen; }
                $numEnd = ($numEndComma < $numEndArrow ? $numEndComma : $numEndArrow);
                $num = trim(substr($str, $ptr, $numEnd - $ptr));
                if (is_numeric($num)) {
                    $scalars[] = $num + 0;
                } else {
                    user_error("Invalid numeric '$num' at $ptr", E_USER_WARNING);
                    return;
                }
                $stack[] = CMS_SCALAR;
                $ptr = $numEnd - 1;
            } elseif ($ptrChar == ',') {
                $stack[] = CMS_COMMA;
            } elseif ($ptrChar == '=') {
                $stack[] = CMS_ARROW;
            } elseif(preg_match('/t/i', $ptrChar)) {
                $stack[] = CMS_SCALAR;
                $scalars[] = TRUE;
            } elseif(preg_match('/f/i', $ptrChar)) {
                $stack[] = CMS_SCALAR;
                $scalars[] = FALSE;
            } elseif(preg_match('/n/i', $ptrChar)) {
                $stack[] = CMS_SCALAR;
                $scalars[] = NULL;
            } else {
                user_error("Invalid character at $ptr", E_USER_WARNING);
                return NULL;
            }
        }
        ++$ptr;
    }
    if (sizeof($scalars == 1)) { //it was singular variable
        return $scalars[0];
    } else {
        return $scalars;
    }
}

« previous php.general (#212044) next »