Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 05b84b1

Browse files
[Cache] Improve perf of array-based pools
1 parent 5c338cc commit 05b84b1

File tree

4 files changed

+98
-28
lines changed

4 files changed

+98
-28
lines changed

src/Symfony/Component/Cache/Adapter/ArrayAdapter.php

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,9 +62,9 @@ public function getItem($key)
6262
$this->values[$key] = $value = null;
6363
} elseif (!$this->storeSerialized) {
6464
$value = $this->values[$key];
65-
} elseif ('b:0;' === $value = $this->values[$key]) {
66-
$value = false;
67-
} elseif (false === $value = unserialize($value)) {
65+
} elseif ('N;' === $value = $this->values[$key]) {
66+
$value = null;
67+
} elseif (\is_string($value) && isset($value[2]) && ':' === $value[1] && false === $value = unserialize($value)) {
6868
$this->values[$key] = $value = null;
6969
$isHit = false;
7070
}
@@ -84,7 +84,9 @@ public function getItem($key)
8484
public function getItems(array $keys = array())
8585
{
8686
foreach ($keys as $key) {
87-
CacheItem::validateKey($key);
87+
if (!\is_string($key) || !isset($this->expiries[$key])) {
88+
CacheItem::validateKey($key);
89+
}
8890
}
8991

9092
return $this->generateItems($keys, microtime(true), $this->createCacheItem);
@@ -120,15 +122,26 @@ public function save(CacheItemInterface $item)
120122

121123
return true;
122124
}
123-
if ($this->storeSerialized) {
124-
try {
125+
if (!$this->storeSerialized) {
126+
// no-op
127+
} elseif (\is_string($value)) {
128+
// Serialize strings if they could be confused with serialized objects or arrays
129+
if ('N;' === $value || (isset($value[2]) && ':' === $value[1])) {
125130
$value = serialize($value);
131+
}
132+
} elseif (null !== $value && !\is_scalar($value)) {
133+
try {
134+
$serialized = serialize($value);
126135
} catch (\Exception $e) {
127136
$type = is_object($value) ? get_class($value) : gettype($value);
128137
CacheItem::log($this->logger, 'Failed to save key "{key}" ({type})', array('key' => $key, 'type' => $type, 'exception' => $e));
129138

130139
return false;
131140
}
141+
// Keep value serialized if it contains any objects or any internal references
142+
if ('C' === $serialized[0] || 'O' === $serialized[0] || preg_match('/;[OCRr]:[1-9]/', $serialized)) {
143+
$value = $serialized;
144+
}
132145
}
133146
if (null === $expiry && 0 < $item["\0*\0defaultLifetime"]) {
134147
$expiry = microtime(true) + $item["\0*\0defaultLifetime"];

src/Symfony/Component/Cache/Simple/ArrayCache.php

Lines changed: 51 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -45,9 +45,33 @@ public function __construct(int $defaultLifetime = 0, bool $storeSerialized = tr
4545
*/
4646
public function get($key, $default = null)
4747
{
48-
foreach ($this->getMultiple(array($key), $default) as $v) {
49-
return $v;
48+
if (!\is_string($key) || !isset($this->expiries[$key])) {
49+
CacheItem::validateKey($key);
50+
}
51+
if (!isset($this->expiries[$key]) || ($this->expiries[$key] <= microtime(true) && $this->deleteItem($key))) {
52+
$this->values[$key] = null;
53+
54+
return $default;
55+
}
56+
if (!$this->storeSerialized) {
57+
return $this->values[$key];
58+
}
59+
if ('N;' === $value = $this->values[$key]) {
60+
return null;
61+
}
62+
if (!\is_string($value) || !isset($value[2]) || ':' !== $value[1]) {
63+
return $value;
5064
}
65+
try {
66+
if (false !== $value = unserialize($value)) {
67+
return $value;
68+
}
69+
} catch (\Exception $e) {
70+
CacheItem::log($this->logger, 'Failed to unserialize key "{key}"', array('key' => $key, 'exception' => $e));
71+
}
72+
$this->values[$key] = null;
73+
74+
return $default;
5175
}
5276

5377
/**
@@ -61,7 +85,9 @@ public function getMultiple($keys, $default = null)
6185
throw new InvalidArgumentException(sprintf('Cache keys must be array or Traversable, "%s" given', is_object($keys) ? get_class($keys) : gettype($keys)));
6286
}
6387
foreach ($keys as $key) {
64-
CacheItem::validateKey($key);
88+
if (!\is_string($key) || !isset($this->expiries[$key])) {
89+
CacheItem::validateKey($key);
90+
}
6591
}
6692

6793
return $this->generateItems($keys, microtime(true), function ($k, $v, $hit) use ($default) { return $hit ? $v : $default; });
@@ -87,7 +113,9 @@ public function deleteMultiple($keys)
87113
*/
88114
public function set($key, $value, $ttl = null)
89115
{
90-
CacheItem::validateKey($key);
116+
if (!\is_string($key)) {
117+
CacheItem::validateKey($key);
118+
}
91119

92120
return $this->setMultiple(array($key => $value), $ttl);
93121
}
@@ -103,27 +131,38 @@ public function setMultiple($values, $ttl = null)
103131
$valuesArray = array();
104132

105133
foreach ($values as $key => $value) {
106-
\is_int($key) || CacheItem::validateKey($key);
134+
if (!\is_int($key) && !(\is_string($key) && isset($this->expiries[$key]))) {
135+
CacheItem::validateKey($key);
136+
}
107137
$valuesArray[$key] = $value;
108138
}
109139
if (false === $ttl = $this->normalizeTtl($ttl)) {
110140
return $this->deleteMultiple(array_keys($valuesArray));
111141
}
112-
if ($this->storeSerialized) {
113-
foreach ($valuesArray as $key => $value) {
142+
$expiry = 0 < $ttl ? microtime(true) + $ttl : PHP_INT_MAX;
143+
144+
foreach ($valuesArray as $key => $value) {
145+
if (!$this->storeSerialized) {
146+
// no-op
147+
} elseif (\is_string($value)) {
148+
// Serialize strings if they could be confused with serialized objects or arrays
149+
if ('N;' === $value || (isset($value[2]) && ':' === $value[1])) {
150+
$value = serialize($value);
151+
}
152+
} elseif (null !== $value && !\is_scalar($value)) {
114153
try {
115-
$valuesArray[$key] = serialize($value);
154+
$serialized = serialize($value);
116155
} catch (\Exception $e) {
117156
$type = is_object($value) ? get_class($value) : gettype($value);
118157
CacheItem::log($this->logger, 'Failed to save key "{key}" ({type})', array('key' => $key, 'type' => $type, 'exception' => $e));
119158

120159
return false;
121160
}
161+
// Keep value serialized if it contains any objects or any internal references
162+
if ('C' === $serialized[0] || 'O' === $serialized[0] || preg_match('/;[OCRr]:[1-9]/', $serialized)) {
163+
$value = $serialized;
164+
}
122165
}
123-
}
124-
$expiry = 0 < $ttl ? microtime(true) + $ttl : PHP_INT_MAX;
125-
126-
foreach ($valuesArray as $key => $value) {
127166
$this->values[$key] = $value;
128167
$this->expiries[$key] = $expiry;
129168
}

src/Symfony/Component/Cache/Tests/Adapter/ArrayAdapterTest.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,12 @@ public function testGetValuesHitAndMiss()
3636

3737
// Hit
3838
$item = $cache->getItem('foo');
39-
$item->set('4711');
39+
$item->set('::4711');
4040
$cache->save($item);
4141

4242
$fooItem = $cache->getItem('foo');
4343
$this->assertTrue($fooItem->isHit());
44-
$this->assertEquals('4711', $fooItem->get());
44+
$this->assertEquals('::4711', $fooItem->get());
4545

4646
// Miss (should be present as NULL in $values)
4747
$cache->getItem('bar');
@@ -50,7 +50,7 @@ public function testGetValuesHitAndMiss()
5050

5151
$this->assertCount(2, $values);
5252
$this->assertArrayHasKey('foo', $values);
53-
$this->assertSame(serialize('4711'), $values['foo']);
53+
$this->assertSame(serialize('::4711'), $values['foo']);
5454
$this->assertArrayHasKey('bar', $values);
5555
$this->assertNull($values['bar']);
5656
}

src/Symfony/Component/Cache/Traits/ArrayTrait.php

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,17 +34,34 @@ trait ArrayTrait
3434
*/
3535
public function getValues()
3636
{
37-
return $this->values;
37+
if (!$this->storeSerialized) {
38+
return $this->values;
39+
}
40+
41+
$values = $this->values;
42+
foreach ($values as $k => $v) {
43+
if (null === $v || 'N;' === $v) {
44+
continue;
45+
}
46+
if (!\is_string($v) || !isset($v[2]) || ':' !== $v[1]) {
47+
$values[$k] = serialize($v);
48+
}
49+
}
50+
51+
return $values;
3852
}
3953

4054
/**
4155
* {@inheritdoc}
4256
*/
4357
public function hasItem($key)
4458
{
59+
if (\is_string($key) && isset($this->expiries[$key]) && $this->expiries[$key] > microtime(true)) {
60+
return true;
61+
}
4562
CacheItem::validateKey($key);
4663

47-
return isset($this->expiries[$key]) && ($this->expiries[$key] > microtime(true) || !$this->deleteItem($key));
64+
return isset($this->expiries[$key]) && !$this->deleteItem($key);
4865
}
4966

5067
/**
@@ -62,8 +79,9 @@ public function clear()
6279
*/
6380
public function deleteItem($key)
6481
{
65-
CacheItem::validateKey($key);
66-
82+
if (!\is_string($key) || !isset($this->expiries[$key])) {
83+
CacheItem::validateKey($key);
84+
}
6785
unset($this->values[$key], $this->expiries[$key]);
6886

6987
return true;
@@ -85,9 +103,9 @@ private function generateItems(array $keys, $now, $f)
85103
$this->values[$key] = $value = null;
86104
} elseif (!$this->storeSerialized) {
87105
$value = $this->values[$key];
88-
} elseif ('b:0;' === $value = $this->values[$key]) {
89-
$value = false;
90-
} elseif (false === $value = unserialize($value)) {
106+
} elseif ('N;' === $value = $this->values[$key]) {
107+
$value = null;
108+
} elseif (\is_string($value) && isset($value[2]) && ':' === $value[1] && false === $value = unserialize($value)) {
91109
$this->values[$key] = $value = null;
92110
$isHit = false;
93111
}

0 commit comments

Comments
 (0)