1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* |
4
|
|
|
Copyright (C) 2006-2014 David Négrier - THE CODING MACHINE |
5
|
|
|
|
6
|
|
|
This program is free software; you can redistribute it and/or modify |
7
|
|
|
it under the terms of the GNU General Public License as published by |
8
|
|
|
the Free Software Foundation; either version 2 of the License, or |
9
|
|
|
(at your option) any later version. |
10
|
|
|
|
11
|
|
|
This program is distributed in the hope that it will be useful, |
12
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
13
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
14
|
|
|
GNU General Public License for more details. |
15
|
|
|
|
16
|
|
|
You should have received a copy of the GNU General Public License |
17
|
|
|
along with this program; if not, write to the Free Software |
18
|
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
19
|
|
|
*/ |
20
|
|
|
|
21
|
|
|
namespace Mouf\Database\TDBM; |
22
|
|
|
|
23
|
|
|
/** |
24
|
|
|
* The WeakrefObjectStorage class is used to reference all beans that have been fetched from the database. |
25
|
|
|
* If a bean is requested twice from TDBM, the WeakrefObjectStorage is used to "cache" the bean. |
26
|
|
|
* Unlike the StandardObjectStorage, the WeakrefObjectStorage manages memory in a clever way, using the weakref |
27
|
|
|
* PHP extension. It is used if the "weakref" extension is available. |
28
|
|
|
* Otherwise, the StandardObjectStorage is used instead. |
29
|
|
|
* |
30
|
|
|
* @author David Negrier |
31
|
|
|
*/ |
32
|
|
|
class WeakrefObjectStorage |
33
|
|
|
{ |
34
|
|
|
/** |
35
|
|
|
* An array of fetched object, accessible via table name and primary key. |
36
|
|
|
* If the primary key is split on several columns, access is done by an array of columns, serialized. |
37
|
|
|
* |
38
|
|
|
* @var array<string, WeakMap<string, TDBMObject>> |
39
|
|
|
*/ |
40
|
|
|
private $objects = array(); |
41
|
|
|
|
42
|
|
|
/** |
43
|
|
|
* Every 10000 set in the dataset, we perform a cleanup to ensure the WeakRef instances |
44
|
|
|
* are removed if they are no more valid. |
45
|
|
|
* This is to avoid having memory used by dangling WeakRef instances. |
46
|
|
|
* |
47
|
|
|
* @var int |
48
|
|
|
*/ |
49
|
|
|
private $garbageCollectorCount = 0; |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* Sets an object in the storage. |
53
|
|
|
* |
54
|
|
|
* @param string $tableName |
55
|
|
|
* @param string $id |
56
|
|
|
* @param DbRow $dbRow |
57
|
|
|
*/ |
58
|
|
|
public function set($tableName, $id, DbRow $dbRow) |
59
|
|
|
{ |
60
|
|
|
$this->objects[$tableName][$id] = new \WeakRef($dbRow); |
61
|
|
|
++$this->garbageCollectorCount; |
62
|
|
|
if ($this->garbageCollectorCount == 10000) { |
63
|
|
|
$this->garbageCollectorCount = 0; |
64
|
|
|
$this->cleanupDanglingWeakRefs(); |
65
|
|
|
} |
66
|
|
|
} |
67
|
|
|
|
68
|
|
|
/** |
69
|
|
|
* Checks if an object is in the storage. |
70
|
|
|
* |
71
|
|
|
* @param string $tableName |
72
|
|
|
* @param string $id |
73
|
|
|
* |
74
|
|
|
* @return bool |
75
|
|
|
*/ |
76
|
|
|
public function has($tableName, $id) |
77
|
|
|
{ |
78
|
|
View Code Duplication |
if (isset($this->objects[$tableName][$id])) { |
|
|
|
|
79
|
|
|
if ($this->objects[$tableName][$id]->valid()) { |
80
|
|
|
return true; |
81
|
|
|
} else { |
82
|
|
|
unset($this->objects[$tableName][$id]); |
83
|
|
|
} |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
return false; |
87
|
|
|
} |
88
|
|
|
|
89
|
|
|
/** |
90
|
|
|
* Returns an object from the storage (or null if no object is set). |
91
|
|
|
* |
92
|
|
|
* @param string $tableName |
93
|
|
|
* @param string $id |
94
|
|
|
* |
95
|
|
|
* @return DbRow |
96
|
|
|
*/ |
97
|
|
|
public function get($tableName, $id) |
98
|
|
|
{ |
99
|
|
View Code Duplication |
if (isset($this->objects[$tableName][$id])) { |
|
|
|
|
100
|
|
|
if ($this->objects[$tableName][$id]->valid()) { |
101
|
|
|
return $this->objects[$tableName][$id]->get(); |
102
|
|
|
} |
103
|
|
|
} else { |
104
|
|
|
return; |
105
|
|
|
} |
106
|
|
|
} |
107
|
|
|
|
108
|
|
|
/** |
109
|
|
|
* Removes an object from the storage. |
110
|
|
|
* |
111
|
|
|
* @param string $tableName |
112
|
|
|
* @param string $id |
113
|
|
|
*/ |
114
|
|
|
public function remove($tableName, $id) |
115
|
|
|
{ |
116
|
|
|
unset($this->objects[$tableName][$id]); |
117
|
|
|
} |
118
|
|
|
|
119
|
|
|
/** |
120
|
|
|
* Applies the callback to all objects. |
121
|
|
|
* |
122
|
|
|
* @param callable $callback |
123
|
|
|
*/ |
124
|
|
|
public function apply(callable $callback) |
125
|
|
|
{ |
126
|
|
|
foreach ($this->objects as $tableName => $table) { |
127
|
|
|
foreach ($table as $id => $obj) { |
128
|
|
|
if ($obj->valid()) { |
129
|
|
|
$callback($obj->get(), $tableName, $id); |
130
|
|
|
} else { |
131
|
|
|
unset($this->objects[$tableName][$id]); |
132
|
|
|
} |
133
|
|
|
} |
134
|
|
|
} |
135
|
|
|
} |
136
|
|
|
|
137
|
|
|
private function cleanupDanglingWeakRefs() |
138
|
|
|
{ |
139
|
|
|
foreach ($this->objects as $tableName => $table) { |
140
|
|
|
foreach ($table as $id => $obj) { |
141
|
|
|
if (!$obj->valid()) { |
142
|
|
|
unset($this->objects[$tableName][$id]); |
143
|
|
|
} |
144
|
|
|
} |
145
|
|
|
} |
146
|
|
|
} |
147
|
|
|
} |
148
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.