Skip to content

Commit

Permalink
feat: new functions (#3)
Browse files Browse the repository at this point in the history
This deprecates the `Castor\Context\with_value` and
`Castor\Context\fallback` functions, and replaces them with
`Castor\Context\withValue` and `Castor\Context\nil`.

The reason behind this change is better and more consistent naming
conventions.
  • Loading branch information
mnavarrocarter authored Oct 28, 2022
1 parent 9bf00ec commit 41eda33
Show file tree
Hide file tree
Showing 8 changed files with 60 additions and 26 deletions.
10 changes: 5 additions & 5 deletions .castor/docs/best-practices.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ to minimize as much as possible the space impact that has in your method's argum

## Enums SHOULD be used as keys rather than strings

When calling `Context\with_value()` prefer enums as keys. They are lightweight, offer autocompletion, and they cannot
When calling `Context\withValue()` prefer enums as keys. They are lightweight, offer autocompletion, and they cannot
collide like strings could. In the case that your application still does not support PHP 8.1 and above, you MUST use
string keys with a vendor namespace.

Expand All @@ -38,18 +38,18 @@ instance, if you are using the `Context` api in PSR-7 applications, it is very l
will be stored in the Request attributes (which is implemented by an array). This is acceptable, but for a better
HTTP layer supporting context natively, we recommend `castor/http`.

## `Context\with_value` SHOULD NOT be overused
## `Context\withValue` SHOULD NOT be overused

Because of its particular implementation, every time you add a value to a `Context`, you increase the potential call
stack size to reach the value by 1. Although the performance impact of this is negligent, is still slower than fetching
a value directly from a map, for instance.

So, bottom line, don't overuse `Context\with_value`. This means that if you have to store related values in
So, bottom line, don't overuse `Context\withValue`. This means that if you have to store related values in
`Context`, store a data structure instead and not each value individually.

Again, the performance impact of not doing this is negligible, so measure and make decisions based on that.

> In a potential new major version, we are considering swapping the `Context\with_value()` implementation by using a
> In a potential new major version, we are considering swapping the `Context\withValue()` implementation by using a
[`DS\Map` if the extension is available](https://www.php.net/manual/en/class.ds-map.php) to avoid the performance
penalty.

Expand All @@ -61,7 +61,7 @@ safe for manipulation and free of unexpected side effects.
As long as `Context` holds values derived from the request, whose lifetime will also die with it, then it is safe to
store mutable values in it. If you store immutable values and decide that a new reference of that value needs to be
passed down the call stack it means the value should have never been immutable in the first place. You'll have to call
`Context\with_value` again and "override" that value.
`Context\withValue` again and "override" that value.

## Services SHOULD NOT be stored inside `Context`

Expand Down
4 changes: 2 additions & 2 deletions .castor/docs/guides.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class TenancyMiddleware implements Handler
}

// Once we have the tenant, we store it in the context
$ctx = Context\with_value($ctx, 'tenant', $tenant);
$ctx = Context\withValue($ctx, 'tenant', $tenant);

// And we pass it to the next handler
$this->next->handle($ctx, $wrt, $req);
Expand Down Expand Up @@ -189,7 +189,7 @@ function with_log_context(Context $ctx, string $key, mixed $value): Context
$logCtx = new LogContext();
$logCtx->add($key, $value);

return Context\with_value($ctx, Key::LOG_CONTEXT, $logCtx);
return Context\withValue($ctx, Key::LOG_CONTEXT, $logCtx);
}

function get_log_context(Context $ctx): LogContext
Expand Down
4 changes: 2 additions & 2 deletions .castor/docs/intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ composer require castor/context

use Castor\Context;

$ctx = Context\fallback(); // This is a default base context
$ctx = Context\with_value($ctx, 'foo', 'bar'); // This returns a new context with the passed values stored
$ctx = Context\nil(); // This is a default base context
$ctx = Context\withValue($ctx, 'foo', 'bar'); // This returns a new context with the passed values stored

// Later in the call stack

Expand Down
12 changes: 6 additions & 6 deletions .castor/docs/why.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,34 +43,34 @@ its internal state like `set(mixed $key, mixed $value): void`. Although we consi
copied from Go the idea to make this interface unavoidably immutable. You can only "store" new values by composing
a new `Context`, and we have provided some functions to ease that process.

## The `Context\fallback()` and the `Context\with_value()` functions
## The `Context\nil()` and the `Context\withValue()` functions

First, in order to "store" a value in the context, you need to get the fallback context. This is some sort of "empty"
context that always returns `null`. You call `Context\fallback()` to do this.
context that always returns `null`. You call `Context\nil()` to do this.

```php
<?php

use Castor\Context;

// This gives you a context that always returns null for any key
$ctx = Context\fallback();
$ctx = Context\nil();

var_dump($ctx->value('foo')); // Prints: NULL
```

Once you have a `Context` instance, you can "store" a value in it by calling `Context\with_value()`:
Once you have a `Context` instance, you can "store" a value in it by calling `Context\withValue()`:

```php
<?php

use Castor\Context;

// This gives you a context that always returns null for any key
$ctx = Context\fallback();
$ctx = Context\nil();

// This returns a new context with the stored key value pair
$ctx = Context\with_value($ctx, 'foo', 'bar');
$ctx = Context\withValue($ctx, 'foo', 'bar');

var_dump($ctx->value('foo')); // Prints: string(3) "bar"
```
Expand Down
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,13 @@ composer require castor/context

use Castor\Context;

$ctx = Context\fallback(); // This is a default base context
$ctx = Context\with_value($ctx, 'foo', 'bar'); // This returns a new context with the passed values stored
// This is a default base context
$ctx = Context\nil();

// Later in the call stack
// This returns a new context with the passed values stored
$ctx = Context\withValue($ctx, 'foo', 'bar');

// Later in the call stack
echo $ctx->value('foo'); // Prints: bar
```

Expand Down
36 changes: 34 additions & 2 deletions functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
*
* @psalm-pure
*/
function with_value(Context $context, mixed $key, mixed $value): Context
function withValue(Context $context, mixed $key, mixed $value): Context
{
return new KVPair($context, $key, $value);
}
Expand All @@ -37,7 +37,39 @@ function with_value(Context $context, mixed $key, mixed $value): Context
*
* @psalm-pure
*/
function fallback(): Context
function nil(): Context
{
return new Value();
}

/**
* Returns a new context that holds the passed key value pair.
*
* @psalm-pure
*
* @deprecated Use Castor\Context\withValue() instead
*/
function with_value(Context $ctx, mixed $key, mixed $value): Context
{
trigger_error('Castor\Context\with_value() is deprecated and it will be removed in a future version. Please use Castor\Context\withValue() instead', E_USER_DEPRECATED);

return withValue($ctx, $key, $value);
}

/**
* Returns the default fallback context.
*
* This is a context that always returns null.
*
* You can think about it as an "empty" context.
*
* @psalm-pure
*
* @deprecated Use Castor\Context\nil() instead
*/
function fallback(): Context
{
trigger_error('Castor\Context\fallback() is deprecated and it will be removed in a future version. Please use Castor\Context\nil() instead', E_USER_DEPRECATED);

return nil();
}
6 changes: 3 additions & 3 deletions tests/Context/KVPairTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ class KVPairTest extends TestCase
{
public function testDebug(): void
{
$ctx = fallback();
$ctx = with_value($ctx, 'foo', 'bar');
$ctx = with_value($ctx, 'bar', 'foo');
$ctx = nil();
$ctx = withValue($ctx, 'foo', 'bar');
$ctx = withValue($ctx, 'bar', 'foo');

$chain = KVPair::debug($ctx);

Expand Down
6 changes: 3 additions & 3 deletions tests/ContextFunctionsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ class ContextFunctionsTest extends TestCase
{
public function testContextFallback(): void
{
$contextA = Context\fallback();
$contextB = Context\fallback();
$contextA = Context\nil();
$contextB = Context\nil();

// Fallback should always return a different instance
$this->assertNotSame($contextA, $contextB);
Expand All @@ -44,7 +44,7 @@ public function testContextFallback(): void
*/
public function testContextWithValue(): void
{
$context = Context\with_value(Context\fallback(), 'foo', 'bar');
$context = Context\withValue(Context\nil(), 'foo', 'bar');

$this->assertSame('bar', $context->value('foo'));
$this->assertNull($context->value('bar'));
Expand Down

0 comments on commit 41eda33

Please sign in to comment.