Dave Jarvis' Repositories

git clone https://repo.autonoma.ca/repo/treetrek.git

Address packed object issue

Author Dave Jarvis <email>
Date 2026-02-18 23:50:17 GMT-0800
Commit e6c04b03c69ac1d72a2486df6822d691dde1479b
Parent f5b2c4d
git/Git.php
}
- public function collectObjects( array $wants, array $haves = [] ): array {
- $objs = [];
- $seen = [];
-
- foreach( $wants as $sha ) {
- $objs = $this->collectObjectsRecursive( $sha, $objs, $seen );
- }
-
- foreach( $haves as $sha ) {
- if( isset( $objs[$sha] ) ) {
- unset( $objs[$sha] );
- }
- }
-
- return $objs;
- }
-
- public function generatePackfile( array $objs ): string {
- $pData = "PACK" . pack( 'N', 2 ) . pack( 'N', 0 );
-
- if( !empty( $objs ) ) {
- $data = '';
-
- foreach( $objs as $sha => $info ) {
- $cont = $this->read( $sha );
- $size = strlen( $cont );
- $byte = $info['type'] << 4 | $size & 0x0f;
- $size >>= 4;
-
- while( $size > 0 ) {
- $data .= chr( $byte | 0x80 );
- $byte = $size & 0x7f;
- $size >>= 7;
- }
-
- $data .= chr( $byte ) . gzcompress( $cont );
- }
-
- $pData = "PACK" . pack( 'N', 2 ) . pack( 'N', count( $objs ) ) . $data;
- }
-
- return $pData . hash( 'sha1', $pData, true );
- }
-
- private function getTreeSha( string $commitOrTreeSha ): string {
- $data = $this->read( $commitOrTreeSha );
- $sha = $commitOrTreeSha;
-
- if( preg_match( '/^object ([0-9a-f]{40})/m', $data, $matches ) ) {
- $sha = $this->getTreeSha( $matches[1] );
- }
-
- if( $sha === $commitOrTreeSha &&
- preg_match( '/^tree ([0-9a-f]{40})/m', $data, $matches ) ) {
- $sha = $matches[1];
- }
-
- return $sha;
- }
-
- private function resolvePath( string $treeSha, string $path ): array {
- $parts = explode( '/', trim( $path, '/' ) );
- $sha = $treeSha;
- $mode = '40000';
-
- foreach( $parts as $part ) {
- $entry = [ 'sha' => '', 'mode' => '' ];
-
- if( $part !== '' && $sha !== '' ) {
- $entry = $this->findTreeEntry( $sha, $part );
- }
-
- $sha = $entry['sha'];
- $mode = $entry['mode'];
- }
-
- return [
- 'sha' => $sha,
- 'mode' => $mode,
- 'isDir' => $mode === '40000' || $mode === '040000'
- ];
- }
-
- private function findTreeEntry( string $treeSha, string $name ): array {
- $data = $this->read( $treeSha );
- $pos = 0;
- $len = strlen( $data );
- $entry = [ 'sha' => '', 'mode' => '' ];
-
- while( $pos < $len ) {
- $space = strpos( $data, ' ', $pos );
- $eos = strpos( $data, "\0", $space );
-
- if( $space === false || $eos === false ) {
- break;
- }
-
- if( substr( $data, $space + 1, $eos - $space - 1 ) === $name ) {
- $entry = [
- 'sha' => bin2hex( substr( $data, $eos + 1, 20 ) ),
- 'mode' => substr( $data, $pos, $space - $pos )
- ];
- break;
- }
-
- $pos = $eos + 21;
- }
-
- return $entry;
- }
-
- private function parseTagData(
- string $name,
- string $sha,
- string $data
- ): Tag {
- $isAnn = strncmp( $data, 'object ', 7 ) === 0;
- $pattern = $isAnn
- ? '/^tagger (.*) <(.*)> (\d+) [+\-]\d{4}$/m'
- : '/^author (.*) <(.*)> (\d+) [+\-]\d{4}$/m';
- $id = $this->parseIdentity( $data, $pattern );
- $target = $isAnn
- ? $this->extractPattern( $data, '/^object (.*)$/m', 1, $sha )
- : $sha;
-
- return new Tag(
- $name,
- $sha,
- $target,
- $id['timestamp'],
- $this->extractMessage( $data ),
- $id['name']
- );
- }
-
- private function extractPattern(
- string $data,
- string $pattern,
- int $group,
- string $default = ''
- ): string {
- return preg_match( $pattern, $data, $matches )
- ? $matches[$group]
- : $default;
- }
-
- private function parseIdentity( string $data, string $pattern ): array {
- $found = preg_match( $pattern, $data, $matches );
-
- return [
- 'name' => $found ? trim( $matches[1] ) : 'Unknown',
- 'email' => $found ? $matches[2] : '',
- 'timestamp' => $found ? (int)$matches[3] : 0
- ];
- }
-
- private function extractMessage( string $data ): string {
- $pos = strpos( $data, "\n\n" );
-
- return $pos !== false ? trim( substr( $data, $pos + 2 ) ) : '';
- }
-
- private function slurp( string $sha, callable $callback ): void {
- $path = $this->getLoosePath( $sha );
-
- if( is_file( $path ) ) {
- $this->slurpLooseObject( $path, $callback );
- } else {
- $this->slurpPackedObject( $sha, $callback );
- }
- }
-
- private function slurpLooseObject( string $path, callable $callback ): void {
- $this->iterateInflated(
- $path,
- function( $chunk ) use ( $callback ) {
- if( $chunk !== '' ) {
- $callback( $chunk );
- }
- return true;
- }
- );
- }
-
- private function slurpPackedObject( string $sha, callable $callback ): void {
- $streamed = $this->packs->stream( $sha, $callback );
-
- if( !$streamed ) {
- $data = $this->packs->read( $sha );
-
- if( $data !== '' ) {
- $callback( $data );
- }
- }
- }
-
- private function iterateInflated(
- string $path,
- callable $processor
- ): void {
- $handle = fopen( $path, 'rb' );
- $infl = $handle ? inflate_init( ZLIB_ENCODING_DEFLATE ) : null;
- $found = false;
- $buffer = '';
-
- if( $handle && $infl ) {
- while( !feof( $handle ) ) {
- $chunk = fread( $handle, 16384 );
- $inflated = inflate_add( $infl, $chunk );
-
- if( $inflated === false ) {
- break;
- }
-
- if( !$found ) {
- $buffer .= $inflated;
- $eos = strpos( $buffer, "\0" );
-
- if( $eos !== false ) {
- $found = true;
- $body = substr( $buffer, $eos + 1 );
- $head = substr( $buffer, 0, $eos );
-
- if( $processor( $body, $head ) === false ) {
- break;
- }
- }
- } elseif( $processor( $inflated, null ) === false ) {
- break;
- }
- }
-
- fclose( $handle );
- }
- }
-
- private function peekLooseObject( string $sha, int $length ): string {
- $path = $this->getLoosePath( $sha );
- $buf = '';
-
- if( is_file( $path ) ) {
- $this->iterateInflated(
- $path,
- function( $chunk ) use ( $length, &$buf ) {
- $buf .= $chunk;
- return strlen( $buf ) < $length;
- }
- );
- }
-
- return substr( $buf, 0, $length );
- }
-
- private function parseCommit( string $sha ): object {
- $data = $this->read( $sha );
- $result = (object)[ 'sha' => '' ];
-
- if( $data !== '' ) {
- $id = $this->parseIdentity(
- $data,
- '/^author (.*) <(.*)> (\d+)/m'
- );
-
- $result = (object)[
- 'sha' => $sha,
- 'message' => $this->extractMessage( $data ),
- 'author' => $id['name'],
- 'email' => $id['email'],
- 'date' => $id['timestamp'],
- 'parentSha' => $this->extractPattern( $data, '/^parent (.*)$/m', 1 )
- ];
- }
-
- return $result;
- }
-
- private function walkTree( string $sha, callable $callback ): void {
- $data = $this->read( $sha );
- $tree = $data;
-
- if( $data !== '' && preg_match( '/^tree (.*)$/m', $data, $m ) ) {
- $tree = $this->read( $m[1] );
- }
-
- if( $tree !== '' && $this->isTreeData( $tree ) ) {
- $this->processTree( $tree, $callback );
- }
- }
-
- private function processTree( string $data, callable $callback ): void {
- $pos = 0;
- $len = strlen( $data );
-
- while( $pos < $len ) {
- $space = strpos( $data, ' ', $pos );
- $eos = strpos( $data, "\0", $space );
- $entry = null;
-
- if( $space !== false && $eos !== false && $eos + 21 <= $len ) {
- $mode = substr( $data, $pos, $space - $pos );
- $sha = bin2hex( substr( $data, $eos + 1, 20 ) );
- $isD = $mode === '40000' || $mode === '040000';
-
- $entry = [
- 'file' => new File(
- substr( $data, $space + 1, $eos - $space - 1 ),
- $sha,
- $mode,
- 0,
- $isD ? 0 : $this->getObjectSize( $sha ),
- $isD ? '' : $this->peek( $sha )
- ),
- 'nextPosition' => $eos + 21
- ];
- }
-
- if( $entry === null ) {
- break;
- }
-
- $callback( $entry['file'] );
- $pos = $entry['nextPosition'];
- }
- }
-
- private function isTreeData( string $data ): bool {
- $len = strlen( $data );
- $patt = '/^(40000|100644|100755|120000|160000) /';
- $match = $len >= 25 && preg_match( $patt, $data );
- $eos = $match ? strpos( $data, "\0" ) : false;
-
- return $match && $eos !== false && $eos + 21 <= $len;
- }
-
- private function getLoosePath( string $sha ): string {
- return "{$this->objPath}/" . substr( $sha, 0, 2 ) . "/" .
- substr( $sha, 2 );
- }
-
- private function getLooseObjectSize( string $sha ): int {
- $path = $this->getLoosePath( $sha );
- $size = 0;
-
- if( is_file( $path ) ) {
- $this->iterateInflated(
- $path,
- function( $c, $head ) use ( &$size ) {
- if( $head !== null ) {
- $parts = explode( ' ', $head );
- $size = isset( $parts[1] ) ? (int)$parts[1] : 0;
- }
- return false;
- }
- );
- }
-
- return $size;
- }
-
- private function collectObjectsRecursive(
- string $sha,
- array $objs,
- array $seen
- ): array {
- if( !isset( $seen[$sha] ) ) {
- $seen[$sha] = true;
- $data = $this->read( $sha );
- $type = $this->getObjectType( $data );
- $objs[$sha] = [ 'type' => $type, 'size' => strlen( $data ) ];
-
- if( $type === 1 ) {
- if( preg_match( '/^tree (.*)$/m', $data, $m ) ) {
- $objs = $this->collectObjectsRecursive( $m[1], $objs, $seen );
- }
- if( preg_match( '/^parent (.*)$/m', $data, $m ) ) {
- $objs = $this->collectObjectsRecursive( $m[1], $objs, $seen );
- }
- }
-
- if( $type === 2 ) {
- $pos = 0;
- $len = strlen( $data );
- while( $pos < $len ) {
- $sp = strpos( $data, ' ', $pos );
- $eos = strpos( $data, "\0", $sp );
- if( $sp === false || $eos === false ) {
- break;
- }
- $s = bin2hex( substr( $data, $eos + 1, 20 ) );
- $objs = $this->collectObjectsRecursive( $s, $objs, $seen );
- $pos = $eos + 21;
- }
- }
-
- if( $type === 4 && preg_match( '/^object (.*)$/m', $data, $m ) ) {
- $objs = $this->collectObjectsRecursive( $m[1], $objs, $seen );
- }
- }
-
- return $objs;
- }
-
- private function getObjectType( string $data ): int {
- $isTree = strpos( $data, "tree " ) === 0;
- $isObj = strpos( $data, "object " ) === 0;
-
- return $isTree
- ? 1
- : ( $this->isTreeData( $data ) ? 2 : ( $isObj ? 4 : 3 ) );
+ public function generatePackfile( array $objs ): string {
+ $pData = "PACK" . pack( 'N', 2 ) . pack( 'N', 0 );
+
+ if( !empty( $objs ) ) {
+ $data = '';
+
+ foreach( $objs as $sha => $info ) {
+ $cont = $this->read( $sha );
+ $size = strlen( $cont );
+ $byte = $info['type'] << 4 | $size & 0x0f;
+ $size >>= 4;
+
+ while( $size > 0 ) {
+ $data .= chr( $byte | 0x80 );
+ $byte = $size & 0x7f;
+ $size >>= 7;
+ }
+
+ $data .= chr( $byte ) . gzcompress( $cont );
+ }
+
+ $pData = "PACK" . pack( 'N', 2 ) . pack( 'N', count( $objs ) ) . $data;
+ }
+
+ return $pData . hash( 'sha1', $pData, true );
+ }
+
+ private function getTreeSha( string $commitOrTreeSha ): string {
+ $data = $this->read( $commitOrTreeSha );
+ $sha = $commitOrTreeSha;
+
+ if( preg_match( '/^object ([0-9a-f]{40})/m', $data, $matches ) ) {
+ $sha = $this->getTreeSha( $matches[1] );
+ }
+
+ if( $sha === $commitOrTreeSha &&
+ preg_match( '/^tree ([0-9a-f]{40})/m', $data, $matches ) ) {
+ $sha = $matches[1];
+ }
+
+ return $sha;
+ }
+
+ private function resolvePath( string $treeSha, string $path ): array {
+ $parts = explode( '/', trim( $path, '/' ) );
+ $sha = $treeSha;
+ $mode = '40000';
+
+ foreach( $parts as $part ) {
+ $entry = [ 'sha' => '', 'mode' => '' ];
+
+ if( $part !== '' && $sha !== '' ) {
+ $entry = $this->findTreeEntry( $sha, $part );
+ }
+
+ $sha = $entry['sha'];
+ $mode = $entry['mode'];
+ }
+
+ return [
+ 'sha' => $sha,
+ 'mode' => $mode,
+ 'isDir' => $mode === '40000' || $mode === '040000'
+ ];
+ }
+
+ private function findTreeEntry( string $treeSha, string $name ): array {
+ $data = $this->read( $treeSha );
+ $pos = 0;
+ $len = strlen( $data );
+ $entry = [ 'sha' => '', 'mode' => '' ];
+
+ while( $pos < $len ) {
+ $space = strpos( $data, ' ', $pos );
+ $eos = strpos( $data, "\0", $space );
+
+ if( $space === false || $eos === false ) {
+ break;
+ }
+
+ if( substr( $data, $space + 1, $eos - $space - 1 ) === $name ) {
+ $entry = [
+ 'sha' => bin2hex( substr( $data, $eos + 1, 20 ) ),
+ 'mode' => substr( $data, $pos, $space - $pos )
+ ];
+ break;
+ }
+
+ $pos = $eos + 21;
+ }
+
+ return $entry;
+ }
+
+ private function parseTagData(
+ string $name,
+ string $sha,
+ string $data
+ ): Tag {
+ $isAnn = strncmp( $data, 'object ', 7 ) === 0;
+ $pattern = $isAnn
+ ? '/^tagger (.*) <(.*)> (\d+) [+\-]\d{4}$/m'
+ : '/^author (.*) <(.*)> (\d+) [+\-]\d{4}$/m';
+ $id = $this->parseIdentity( $data, $pattern );
+ $target = $isAnn
+ ? $this->extractPattern( $data, '/^object (.*)$/m', 1, $sha )
+ : $sha;
+
+ return new Tag(
+ $name,
+ $sha,
+ $target,
+ $id['timestamp'],
+ $this->extractMessage( $data ),
+ $id['name']
+ );
+ }
+
+ private function extractPattern(
+ string $data,
+ string $pattern,
+ int $group,
+ string $default = ''
+ ): string {
+ return preg_match( $pattern, $data, $matches )
+ ? $matches[$group]
+ : $default;
+ }
+
+ private function parseIdentity( string $data, string $pattern ): array {
+ $found = preg_match( $pattern, $data, $matches );
+
+ return [
+ 'name' => $found ? trim( $matches[1] ) : 'Unknown',
+ 'email' => $found ? $matches[2] : '',
+ 'timestamp' => $found ? (int)$matches[3] : 0
+ ];
+ }
+
+ private function extractMessage( string $data ): string {
+ $pos = strpos( $data, "\n\n" );
+
+ return $pos !== false ? trim( substr( $data, $pos + 2 ) ) : '';
+ }
+
+ private function slurp( string $sha, callable $callback ): void {
+ $path = $this->getLoosePath( $sha );
+
+ if( is_file( $path ) ) {
+ $this->slurpLooseObject( $path, $callback );
+ } else {
+ $this->slurpPackedObject( $sha, $callback );
+ }
+ }
+
+ private function slurpLooseObject( string $path, callable $callback ): void {
+ $this->iterateInflated(
+ $path,
+ function( $chunk ) use ( $callback ) {
+ if( $chunk !== '' ) {
+ $callback( $chunk );
+ }
+ return true;
+ }
+ );
+ }
+
+ private function slurpPackedObject( string $sha, callable $callback ): void {
+ $streamed = $this->packs->stream( $sha, $callback );
+
+ if( !$streamed ) {
+ $data = $this->packs->read( $sha );
+
+ if( $data !== '' ) {
+ $callback( $data );
+ }
+ }
+ }
+
+ private function iterateInflated(
+ string $path,
+ callable $processor
+ ): void {
+ $handle = fopen( $path, 'rb' );
+ $infl = $handle ? inflate_init( ZLIB_ENCODING_DEFLATE ) : null;
+ $found = false;
+ $buffer = '';
+
+ if( $handle && $infl ) {
+ while( !feof( $handle ) ) {
+ $chunk = fread( $handle, 16384 );
+ $inflated = inflate_add( $infl, $chunk );
+
+ if( $inflated === false ) {
+ break;
+ }
+
+ if( !$found ) {
+ $buffer .= $inflated;
+ $eos = strpos( $buffer, "\0" );
+
+ if( $eos !== false ) {
+ $found = true;
+ $body = substr( $buffer, $eos + 1 );
+ $head = substr( $buffer, 0, $eos );
+
+ if( $processor( $body, $head ) === false ) {
+ break;
+ }
+ }
+ } elseif( $processor( $inflated, null ) === false ) {
+ break;
+ }
+ }
+
+ fclose( $handle );
+ }
+ }
+
+ private function peekLooseObject( string $sha, int $length ): string {
+ $path = $this->getLoosePath( $sha );
+ $buf = '';
+
+ if( is_file( $path ) ) {
+ $this->iterateInflated(
+ $path,
+ function( $chunk ) use ( $length, &$buf ) {
+ $buf .= $chunk;
+ return strlen( $buf ) < $length;
+ }
+ );
+ }
+
+ return substr( $buf, 0, $length );
+ }
+
+ private function parseCommit( string $sha ): object {
+ $data = $this->read( $sha );
+ $result = (object)[ 'sha' => '' ];
+
+ if( $data !== '' ) {
+ $id = $this->parseIdentity(
+ $data,
+ '/^author (.*) <(.*)> (\d+)/m'
+ );
+
+ $result = (object)[
+ 'sha' => $sha,
+ 'message' => $this->extractMessage( $data ),
+ 'author' => $id['name'],
+ 'email' => $id['email'],
+ 'date' => $id['timestamp'],
+ 'parentSha' => $this->extractPattern( $data, '/^parent (.*)$/m', 1 )
+ ];
+ }
+
+ return $result;
+ }
+
+ private function walkTree( string $sha, callable $callback ): void {
+ $data = $this->read( $sha );
+ $tree = $data;
+
+ if( $data !== '' && preg_match( '/^tree (.*)$/m', $data, $m ) ) {
+ $tree = $this->read( $m[1] );
+ }
+
+ if( $tree !== '' && $this->isTreeData( $tree ) ) {
+ $this->processTree( $tree, $callback );
+ }
+ }
+
+ private function processTree( string $data, callable $callback ): void {
+ $pos = 0;
+ $len = strlen( $data );
+
+ while( $pos < $len ) {
+ $space = strpos( $data, ' ', $pos );
+ $eos = strpos( $data, "\0", $space );
+ $entry = null;
+
+ if( $space !== false && $eos !== false && $eos + 21 <= $len ) {
+ $mode = substr( $data, $pos, $space - $pos );
+ $sha = bin2hex( substr( $data, $eos + 1, 20 ) );
+ $isD = $mode === '40000' || $mode === '040000';
+
+ $entry = [
+ 'file' => new File(
+ substr( $data, $space + 1, $eos - $space - 1 ),
+ $sha,
+ $mode,
+ 0,
+ $isD ? 0 : $this->getObjectSize( $sha ),
+ $isD ? '' : $this->peek( $sha )
+ ),
+ 'nextPosition' => $eos + 21
+ ];
+ }
+
+ if( $entry === null ) {
+ break;
+ }
+
+ $callback( $entry['file'] );
+ $pos = $entry['nextPosition'];
+ }
+ }
+
+ private function isTreeData( string $data ): bool {
+ $len = strlen( $data );
+ $patt = '/^(40000|100644|100755|120000|160000) /';
+ $match = $len >= 25 && preg_match( $patt, $data );
+ $eos = $match ? strpos( $data, "\0" ) : false;
+
+ return $match && $eos !== false && $eos + 21 <= $len;
+ }
+
+ private function getLoosePath( string $sha ): string {
+ return "{$this->objPath}/" . substr( $sha, 0, 2 ) . "/" .
+ substr( $sha, 2 );
+ }
+
+ private function getLooseObjectSize( string $sha ): int {
+ $path = $this->getLoosePath( $sha );
+ $size = 0;
+
+ if( is_file( $path ) ) {
+ $this->iterateInflated(
+ $path,
+ function( $c, $head ) use ( &$size ) {
+ if( $head !== null ) {
+ $parts = explode( ' ', $head );
+ $size = isset( $parts[1] ) ? (int)$parts[1] : 0;
+ }
+ return false;
+ }
+ );
+ }
+
+ return $size;
+ }
+
+ public function collectObjects( array $wants, array $haves = [] ): array {
+ $objs = [];
+ $result = [];
+
+ foreach( $wants as $sha ) {
+ $objs = $this->collectObjectsRecursive( $sha, $objs, 0 );
+ }
+
+ foreach( $haves as $sha ) {
+ if( isset( $objs[$sha] ) ) {
+ unset( $objs[$sha] );
+ }
+ }
+
+ $result = $objs;
+
+ return $result;
+ }
+
+ private function collectObjectsRecursive(
+ string $sha,
+ array $objs,
+ int $expectedType = 0
+ ): array {
+ $result = $objs;
+
+ if( !isset( $result[$sha] ) ) {
+ $data = $this->read( $sha );
+ $type = $expectedType === 0
+ ? $this->getObjectType( $data )
+ : $expectedType;
+
+ $result[$sha] = [
+ 'type' => $type,
+ 'size' => strlen( $data )
+ ];
+
+ if( $type === 1 ) {
+ $hasTree = preg_match( '/^tree ([0-9a-f]{40})/m', $data, $m );
+
+ if( $hasTree ) {
+ $result = $this->collectObjectsRecursive( $m[1], $result, 2 );
+ }
+
+ $hasParents = preg_match_all(
+ '/^parent ([0-9a-f]{40})/m',
+ $data,
+ $m
+ );
+
+ if( $hasParents ) {
+ foreach( $m[1] as $parentSha ) {
+ $result = $this->collectObjectsRecursive(
+ $parentSha,
+ $result,
+ 1
+ );
+ }
+ }
+ }
+
+ if( $type === 2 ) {
+ $pos = 0;
+ $len = strlen( $data );
+
+ while( $pos < $len ) {
+ $sp = strpos( $data, ' ', $pos );
+ $eos = strpos( $data, "\0", $sp );
+
+ if( $sp === false || $eos === false ) {
+ break;
+ }
+
+ $mode = substr( $data, $pos, $sp - $pos );
+ $s = bin2hex( substr( $data, $eos + 1, 20 ) );
+ $isDir = $mode === '40000' || $mode === '040000';
+ $nextType = $isDir ? 2 : 3;
+ $pos = $eos + 21;
+
+ $result = $this->collectObjectsRecursive(
+ $s,
+ $result,
+ $nextType
+ );
+ }
+ }
+
+ $isTagTarget = $type === 4 &&
+ preg_match( '/^object ([0-9a-f]{40})/m', $data, $m );
+
+ if( $isTagTarget ) {
+ $nextType = 1;
+
+ if( preg_match( '/^type (commit|tree|blob|tag)/m', $data, $t ) ) {
+ $map = [
+ 'commit' => 1,
+ 'tree' => 2,
+ 'blob' => 3,
+ 'tag' => 4
+ ];
+
+ $nextType = $map[$t[1]] ?? 1;
+ }
+
+ $result = $this->collectObjectsRecursive(
+ $m[1],
+ $result,
+ $nextType
+ );
+ }
+ }
+
+ return $result;
+ }
+
+ private function getObjectType( string $data ): int {
+ $isTree = strpos( $data, "tree " ) === 0;
+ $isObj = strpos( $data, "object " ) === 0;
+ $result = 3;
+
+ if( $isTree ) {
+ $result = 1;
+ } elseif( $isObj ) {
+ $result = 4;
+ } elseif( $this->isTreeData( $data ) ) {
+ $result = 2;
+ }
+
+ return $result;
}
}
Delta 471 lines added, 409 lines removed, 62-line increase