@@ -32,21 +32,37 @@ final class Lock implements LockInterface, LoggerAwareInterface
3232 private $ store ;
3333 private $ key ;
3434 private $ ttl ;
35+ private $ autoRelease ;
36+ private $ dirty = false ;
3537
3638 /**
37- * @param Key $key
38- * @param StoreInterface $store
39- * @param float|null $ttl
39+ * @param Key $key Resource to lock
40+ * @param StoreInterface $store Store used to handle lock persistence
41+ * @param float|null $ttl Maximum expected lock duration in seconds
42+ * @param bool $autoRelease Whether to automatically release the lock or not when the lock instance is destroyed
4043 */
41- public function __construct (Key $ key , StoreInterface $ store , $ ttl = null )
44+ public function __construct (Key $ key , StoreInterface $ store , $ ttl = null , $ autoRelease = true )
4245 {
4346 $ this ->store = $ store ;
4447 $ this ->key = $ key ;
4548 $ this ->ttl = $ ttl ;
49+ $ this ->autoRelease = (bool ) $ autoRelease ;
4650
4751 $ this ->logger = new NullLogger ();
4852 }
4953
54+ /**
55+ * Automatically releases the underlying lock when the object is destructed.
56+ */
57+ public function __destruct ()
58+ {
59+ if (!$ this ->autoRelease || !$ this ->dirty || !$ this ->isAcquired ()) {
60+ return ;
61+ }
62+
63+ $ this ->release ();
64+ }
65+
5066 /**
5167 * {@inheritdoc}
5268 */
@@ -59,6 +75,7 @@ public function acquire($blocking = false)
5975 $ this ->store ->waitAndSave ($ this ->key );
6076 }
6177
78+ $ this ->dirty = true ;
6279 $ this ->logger ->info ('Successfully acquired the "{resource}" lock. ' , array ('resource ' => $ this ->key ));
6380
6481 if ($ this ->ttl ) {
@@ -71,6 +88,7 @@ public function acquire($blocking = false)
7188
7289 return true ;
7390 } catch (LockConflictedException $ e ) {
91+ $ this ->dirty = false ;
7492 $ this ->logger ->warning ('Failed to acquire the "{resource}" lock. Someone else already acquired the lock. ' , array ('resource ' => $ this ->key ));
7593
7694 if ($ blocking ) {
@@ -96,13 +114,15 @@ public function refresh()
96114 try {
97115 $ this ->key ->resetLifetime ();
98116 $ this ->store ->putOffExpiration ($ this ->key , $ this ->ttl );
117+ $ this ->dirty = true ;
99118
100119 if ($ this ->key ->isExpired ()) {
101120 throw new LockExpiredException (sprintf ('Failed to put off the expiration of the "%s" lock within the specified time. ' , $ this ->key ));
102121 }
103122
104123 $ this ->logger ->info ('Expiration defined for "{resource}" lock for "{ttl}" seconds. ' , array ('resource ' => $ this ->key , 'ttl ' => $ this ->ttl ));
105124 } catch (LockConflictedException $ e ) {
125+ $ this ->dirty = false ;
106126 $ this ->logger ->warning ('Failed to define an expiration for the "{resource}" lock, someone else acquired the lock. ' , array ('resource ' => $ this ->key ));
107127 throw $ e ;
108128 } catch (\Exception $ e ) {
@@ -116,7 +136,7 @@ public function refresh()
116136 */
117137 public function isAcquired ()
118138 {
119- return $ this ->store ->exists ($ this ->key );
139+ return $ this ->dirty = $ this -> store ->exists ($ this ->key );
120140 }
121141
122142 /**
@@ -125,6 +145,7 @@ public function isAcquired()
125145 public function release ()
126146 {
127147 $ this ->store ->delete ($ this ->key );
148+ $ this ->dirty = false ;
128149
129150 if ($ this ->store ->exists ($ this ->key )) {
130151 $ this ->logger ->warning ('Failed to release the "{resource}" lock. ' , array ('resource ' => $ this ->key ));
0 commit comments