Skip to content

Commit d568614

Browse files
committed
Store metadata in objects instead of arrays
- Store metadata in PHP classes directly instead of arrays (3x performance improvement) - Remove metadata filtering from build process (was never used by PHP) - Remove Metadata Loader (not needed when autoloading metadata classes)
1 parent 3a7e98f commit d568614

File tree

615 files changed

+33501
-58605
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

615 files changed

+33501
-58605
lines changed

.gitattributes

+1
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ phpunit.xml.dist export-ignore
1010
.github/ export-ignore
1111
src/CountryCodeToRegionCodeMapForTesting.php export-ignore
1212
phpstan.neon.dist export-ignore
13+
infection.json5 export-ignore
1314

1415
* text=auto

build.xml

+4-8
Original file line numberDiff line numberDiff line change
@@ -120,10 +120,9 @@
120120
<arg value="BuildMetadataPHPFromXML"/>
121121
<arg value="${git.path}/resources/PhoneNumberMetadataForTesting.xml"/>
122122
<arg value="${data.testCoreData}"/>
123-
<arg value="PhoneNumberMetadataForTesting"/>
123+
<arg value="libphonenumber\\Tests\\core\\data\\PhoneNumberMetadataForTesting"/>
124124
<arg value="CountryCodeToRegionCodeMapForTesting"/>
125125
<arg value="src/"/>
126-
<arg value="false"/>
127126
</exec>
128127
</target>
129128

@@ -149,10 +148,9 @@
149148
<arg value="BuildMetadataPHPFromXML"/>
150149
<arg value="${git.path}/resources/PhoneNumberMetadata.xml"/>
151150
<arg value="${data.coreData}"/>
152-
<arg value="PhoneNumberMetadata"/>
151+
<arg value="libphonenumber\\data\\PhoneNumberMetadata"/>
153152
<arg value="CountryCodeToRegionCodeMap"/>
154153
<arg value="src/"/>
155-
<arg value="false"/>
156154
</exec>
157155
</target>
158156

@@ -161,10 +159,9 @@
161159
<arg value="BuildMetadataPHPFromXML"/>
162160
<arg value="${git.path}/resources/ShortNumberMetadata.xml"/>
163161
<arg value="${data.coreData}"/>
164-
<arg value="ShortNumberMetadata"/>
162+
<arg value="libphonenumber\\data\\ShortNumberMetadata"/>
165163
<arg value="ShortNumbersRegionCodeSet"/>
166164
<arg value="src/"/>
167-
<arg value="false"/>
168165
</exec>
169166
</target>
170167

@@ -173,10 +170,9 @@
173170
<arg value="BuildMetadataPHPFromXML"/>
174171
<arg value="${git.path}/resources/PhoneNumberAlternateFormats.xml"/>
175172
<arg value="${data.coreData}"/>
176-
<arg value="PhoneNumberAlternateFormats"/>
173+
<arg value="libphonenumber\\data\\PhoneNumberAlternateFormats"/>
177174
<arg value="AlternateFormatsCountryCodeSet"/>
178175
<arg value="src/"/>
179-
<arg value="false"/>
180176
</exec>
181177
</target>
182178

build/BuildMetadataFromXml.php

+20-33
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
namespace libphonenumber\buildtools;
66

7+
use libphonenumber\buildtools\Builders\PhoneMetadataBuilder;
78
use libphonenumber\NumberFormat;
8-
use libphonenumber\PhoneMetadata;
99
use libphonenumber\PhoneNumberDesc;
1010
use DOMDocument;
1111
use DOMElement;
@@ -102,9 +102,9 @@ public static function validateRE(string $regex, bool $removeWhitespace = false)
102102
}
103103

104104
/**
105-
* @return PhoneMetadata[]
105+
* @return PhoneMetadataBuilder[]
106106
*/
107-
public static function buildPhoneMetadataCollection(string|DOMElement $inputXmlFile, bool $liteBuild, bool $specialBuild, bool $isShortNumberMetadata = false, bool $isAlternateFormatsMetadata = false): array
107+
public static function buildPhoneMetadataCollection(string|DOMElement $inputXmlFile, bool $isShortNumberMetadata = false, bool $isAlternateFormatsMetadata = false): array
108108
{
109109
if ($inputXmlFile instanceof DOMElement) {
110110
$document = $inputXmlFile;
@@ -120,8 +120,6 @@ public static function buildPhoneMetadataCollection(string|DOMElement $inputXmlF
120120
$territories = $document->getElementsByTagName('territory');
121121
$metadataCollection = [];
122122

123-
$metadataFilter = self::getMetadataFilter($liteBuild, $specialBuild);
124-
125123
foreach ($territories as $territoryElement) {
126124
/** @var DOMElement $territoryElement */
127125
// For the main metadata file this should always be set, but for other supplementary data
@@ -132,13 +130,12 @@ public static function buildPhoneMetadataCollection(string|DOMElement $inputXmlF
132130
$regionCode = '';
133131
}
134132
$metadata = self::loadCountryMetadata($regionCode, $territoryElement, $isShortNumberMetadata, $isAlternateFormatsMetadata);
135-
$metadataFilter->filterMetadata($metadata);
136133
$metadataCollection[] = $metadata;
137134
}
138135
return $metadataCollection;
139136
}
140137

141-
public static function loadCountryMetadata(string $regionCode, DOMElement $element, bool $isShortNumberMetadata, bool $isAlternateFormatsMetadata): PhoneMetadata
138+
public static function loadCountryMetadata(string $regionCode, DOMElement $element, bool $isShortNumberMetadata, bool $isAlternateFormatsMetadata): PhoneMetadataBuilder
142139
{
143140
$nationalPrefix = self::getNationalPrefix($element);
144141
$metadata = self::loadTerritoryTagMetadata($regionCode, $element, $nationalPrefix);
@@ -152,25 +149,6 @@ public static function loadCountryMetadata(string $regionCode, DOMElement $eleme
152149
return $metadata;
153150
}
154151

155-
/**
156-
* Processes the custom build flags and gets a MetadataFilter which may be used to
157-
* filter PhoneMetadata objects. Incompatible flag combinations throw RuntimeException.
158-
*/
159-
public static function getMetadataFilter(bool $liteBuild, bool $specialBuild): MetadataFilter
160-
{
161-
if ($specialBuild) {
162-
if ($liteBuild) {
163-
throw new RuntimeException('liteBuild and specialBuild may not both be set');
164-
}
165-
return MetadataFilter::forSpecialBuild();
166-
}
167-
if ($liteBuild) {
168-
return MetadataFilter::forLiteBuild();
169-
}
170-
171-
return MetadataFilter::emptyFilter();
172-
}
173-
174152
/**
175153
* Returns the national prefix of the provided country element.
176154
*/
@@ -194,8 +172,17 @@ public static function loadTerritoryTagMetadata(
194172
string $regionCode,
195173
DOMElement $element,
196174
string $nationalPrefix
197-
): PhoneMetadata {
198-
$metadata = new PhoneMetadata();
175+
): PhoneMetadataBuilder {
176+
/*
177+
* Create a new class called PhoneMetadataBuilder extending PhoneMetadata
178+
*
179+
* Have a property called $constants. The appropiate setter will set the const
180+
* This class will have all the setters
181+
*
182+
* This class will have a function to write it to PHP
183+
*
184+
*/
185+
$metadata = new PhoneMetadataBuilder();
199186
$metadata->setId($regionCode);
200187
$metadata->setCountryCode((int) $element->getAttribute(self::COUNTRY_CODE));
201188
if ($element->hasAttribute(self::LEADING_DIGITS)) {
@@ -239,7 +226,7 @@ public static function loadTerritoryTagMetadata(
239226
* nationalPrefixOptionalWhenFormatting values are provided from the parent (territory) element.
240227
*/
241228
public static function loadAvailableFormats(
242-
PhoneMetadata $metadata,
229+
PhoneMetadataBuilder $metadata,
243230
DOMElement $element,
244231
string $nationalPrefix,
245232
string $nationalPrefixFormattingRule,
@@ -312,7 +299,7 @@ public static function getDomesticCarrierCodeFormattingRuleFromElement(DOMElemen
312299
* @throws RuntimeException if multiple or no formats have been encountered.
313300
*/
314301
public static function loadNationalFormat(
315-
PhoneMetadata $metadata,
302+
PhoneMetadataBuilder $metadata,
316303
DOMElement $numberFormatElement,
317304
NumberFormat $format
318305
): void {
@@ -347,7 +334,7 @@ public static function setLeadingDigitsPatterns(DOMElement $numberFormatElement,
347334
* @return bool whether an international number format is defined.
348335
*/
349336
public static function loadInternationalFormat(
350-
PhoneMetadata $metadata,
337+
PhoneMetadataBuilder $metadata,
351338
DOMElement $numberFormatElement,
352339
NumberFormat $nationalFormat
353340
): bool {
@@ -379,7 +366,7 @@ public static function loadInternationalFormat(
379366
return $hasExplicitIntlFormatDefined;
380367
}
381368

382-
public static function setRelevantDescPatterns(PhoneMetadata $metadata, DOMElement $element, bool $isShortNumberMetadata): void
369+
public static function setRelevantDescPatterns(PhoneMetadataBuilder $metadata, DOMElement $element, bool $isShortNumberMetadata): void
383370
{
384371
$generalDesc = self::processPhoneNumberDescElement(null, $element, self::GENERAL_DESC);
385372
$metadata->setGeneralDesc($generalDesc);
@@ -722,7 +709,7 @@ private static function arePossibleLengthsEqual(array $possibleLengths, PhoneNum
722709
}
723710

724711
/**
725-
* @param PhoneMetadata[] $metadataCollection
712+
* @param PhoneMetadataBuilder[] $metadataCollection
726713
* @return array<int|string,array<string>>
727714
*/
728715
public static function buildCountryCodeToRegionCodeMap(array $metadataCollection): array

build/BuildMetadataPHPFromXml.php

+55-56
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44

55
namespace libphonenumber\buildtools;
66

7-
use libphonenumber\PhoneMetadata;
8-
use Symfony\Component\VarExporter\VarExporter;
7+
use libphonenumber\buildtools\Builders\PhoneMetadataBuilder;
8+
use Nette\PhpGenerator\PhpFile;
9+
use Nette\PhpGenerator\PsrPrinter;
910

1011
use function array_keys;
1112
use function count;
1213
use function file_put_contents;
1314
use function ksort;
14-
use function lcfirst;
1515

1616
/**
1717
* Tool to convert phone number metadata from the XML format to protocol buffer format.
@@ -22,43 +22,33 @@
2222
class BuildMetadataPHPFromXml
2323
{
2424
public const GENERATION_COMMENT = <<<EOT
25-
/**
26-
* libphonenumber-for-php data file
27-
* This file has been @generated from libphonenumber data
28-
* Do not modify!
29-
* @internal
30-
*/
25+
libphonenumber-for-php data file
26+
This file has been @generated from libphonenumber data
27+
Do not modify!
28+
@internal
3129
3230
EOT;
3331
public const MAP_COMMENT = <<<EOT
34-
/**
35-
* A mapping from a country code to the region codes which denote the
36-
* country/region represented by that country code. In the case of multiple
37-
* countries sharing a calling code, such as the NANPA countries, the one
38-
* indicated with "isMainCountryForCode" in the metadata should be first.
39-
* @var array<int,string[]>
40-
*/
32+
A mapping from a country code to the region codes which denote the
33+
country/region represented by that country code. In the case of multiple
34+
countries sharing a calling code, such as the NANPA countries, the one
35+
indicated with "isMainCountryForCode" in the metadata should be first.
36+
@var array<int,string[]>
4137
4238
EOT;
43-
public const COUNTRY_CODE_SET_COMMENT = <<<php
44-
/**
45-
* A set of all country calling codes for which data is available.
46-
* @var int[]
47-
*/
48-
php;
49-
public const REGION_CODE_SET_COMMENT = <<<php
50-
/**
51-
* A set of all region codes for which data is available.
52-
* @var string[]
53-
*/
54-
php;
55-
56-
public function start(string $inputFile, string $outputDir, string $filePrefix, string $mappingClass, string $mappingClassLocation, bool $liteBuild): void
57-
{
58-
$savePath = $outputDir . $filePrefix;
39+
public const COUNTRY_CODE_SET_COMMENT = <<<EOT
40+
A set of all country calling codes for which data is available.
41+
@var int[]
42+
EOT;
43+
public const REGION_CODE_SET_COMMENT = <<<EOT
44+
A set of all region codes for which data is available.
45+
@var string[]
46+
EOT;
5947

60-
$metadataCollection = BuildMetadataFromXml::buildPhoneMetadataCollection($inputFile, $liteBuild, false);
61-
$this->writeMetadataToFile($metadataCollection, $savePath);
48+
public function start(string $inputFile, string $outputDir, string $namespaceAndClassPrefix, string $mappingClass, string $mappingClassLocation): void
49+
{
50+
$metadataCollection = BuildMetadataFromXml::buildPhoneMetadataCollection($inputFile);
51+
$this->writeMetadataToFile($metadataCollection, $outputDir, $namespaceAndClassPrefix);
6252

6353
$countryCodeToRegionCodeMap = BuildMetadataFromXml::buildCountryCodeToRegionCodeMap($metadataCollection);
6454
// Sort $countryCodeToRegionCodeMap just to have the regions in order
@@ -67,9 +57,9 @@ public function start(string $inputFile, string $outputDir, string $filePrefix,
6757
}
6858

6959
/**
70-
* @param PhoneMetadata[] $metadataCollection
60+
* @param PhoneMetadataBuilder[] $metadataCollection
7161
*/
72-
private function writeMetadataToFile(array $metadataCollection, string $filePrefix): void
62+
private function writeMetadataToFile(array $metadataCollection, string $directory, string $namespaceAndClassPrefix): void
7363
{
7464
foreach ($metadataCollection as $metadata) {
7565
$regionCode = $metadata->getId();
@@ -79,11 +69,17 @@ private function writeMetadataToFile(array $metadataCollection, string $filePref
7969
$regionCode = $metadata->getCountryCode();
8070
}
8171

82-
$data = '<?php' . PHP_EOL
83-
. self::GENERATION_COMMENT . PHP_EOL
84-
. 'return ' . VarExporter::export($metadata->toArray()) . ';' . PHP_EOL;
72+
$pos = strrpos($namespaceAndClassPrefix, '\\');
73+
74+
$namespace = substr($namespaceAndClassPrefix, 0, $pos);
75+
$classPrefix = substr($namespaceAndClassPrefix, $pos + 1);
8576

86-
file_put_contents($filePrefix . '_' . $regionCode . '.php', $data);
77+
$data = $metadata->toFile($classPrefix . '_' . $regionCode, $namespace);
78+
$data->addComment(self::GENERATION_COMMENT);
79+
80+
$printer = new PsrPrinter();
81+
82+
file_put_contents($directory . DIRECTORY_SEPARATOR . $classPrefix . '_' . $regionCode . '.php', $printer->printFile($data));
8783
}
8884
}
8985

@@ -104,29 +100,32 @@ private function writeCountryCallingCodeMappingToFile(array $countryCodeToRegion
104100

105101
$hasCountryCodes = count($countryCodeToRegionCodeMap) > 1;
106102

107-
$variableName = lcfirst($mappingClass);
103+
$variableName = strtoupper(preg_replace('/(?<!^)[A-Z]/', '_$0', $mappingClass));
104+
105+
$file = new PhpFile();
106+
$file->setStrictTypes();
107+
$file->addComment(self::GENERATION_COMMENT);
108108

109-
$data = '<?php' . PHP_EOL .
110-
'declare(strict_types=1);' . PHP_EOL .
111-
'namespace libphonenumber;' . PHP_EOL .
112-
self::GENERATION_COMMENT . PHP_EOL .
113-
"class {$mappingClass} {" . PHP_EOL .
114-
PHP_EOL;
109+
$namespace = $file->addNamespace('libphonenumber');
110+
111+
$class = $namespace->addClass($mappingClass);
112+
$class->addComment('@internal');
115113

116114
if ($hasRegionCodes && $hasCountryCodes) {
117-
$data .= self::MAP_COMMENT . PHP_EOL;
118-
$data .= " public static array \${$variableName} = " . VarExporter::export($countryCodeToRegionCodeMap) . ';' . PHP_EOL;
115+
$constant = $class->addConstant($variableName, $countryCodeToRegionCodeMap);
116+
$constant->setComment(self::MAP_COMMENT);
119117
} elseif ($hasCountryCodes) {
120-
$data .= self::COUNTRY_CODE_SET_COMMENT . PHP_EOL;
121-
$data .= " public static array \${$variableName} = " . VarExporter::export(array_keys($countryCodeToRegionCodeMap)) . ';' . PHP_EOL;
118+
$constant = $class->addConstant($variableName, array_keys($countryCodeToRegionCodeMap));
119+
$constant->setComment(self::COUNTRY_CODE_SET_COMMENT);
122120
} else {
123-
$data .= self::REGION_CODE_SET_COMMENT . PHP_EOL;
124-
$data .= " public static array \${$variableName} = " . VarExporter::export($countryCodeToRegionCodeMap[0]) . ';' . PHP_EOL;
121+
$constant = $class->addConstant($variableName, $countryCodeToRegionCodeMap[0]);
122+
$constant->setComment(self::REGION_CODE_SET_COMMENT);
125123
}
126124

127-
$data .= PHP_EOL .
128-
'}' . PHP_EOL;
125+
$constant->setPublic();
126+
127+
$printer = new PsrPrinter();
129128

130-
file_put_contents($outputDir . $mappingClass . '.php', $data);
129+
file_put_contents($outputDir . $mappingClass . '.php', $printer->printFile($file));
131130
}
132131
}

0 commit comments

Comments
 (0)