Hi Rowan,
Thanks, this is exactly the kind of API-shaping feedback I was hoping for.
Things I'm happy to take:
- Certificate and key as 'OpenSSLCertificate' / 'OpenSSLAsymmetricKey'
objects rather than PEM strings: yes, that aligns with the rest of
ext/openssl. I'd probably still accept PEM as a convenience, but make the
objects the primary form.
- Returning 'null' rather than 'false' for an expected empty result (no
datagram pending, no application data yet): agreed, null is clearer there.
On the enums (the handshake state, and digest selection): I like enums, and
personally I'd reach for them too. My hesitation is that I'd rather not
diverge from how ext/openssl is consolidated today: the extension exposes
this kind of thing as integer constants ('OPENSSL_ALGO_*', 'OPENSSL_*') and
selects digests by name (string), not through enums. Introducing enums just
for DTLS would create a new convention in one corner of the extension.
Whether ext/openssl should move towards enums more broadly feels like a
maintainer-level decision, and Jakub's feedback would be valuable there; he
may well already be considering something along these lines. I'd keep that
question separate from this proposal, so the DTLS work doesn't hinge on a
wider style change, and for now follow the extension's existing convention.
On a 'DtlsDatagram' value object vs raw strings: here I'd lean towards
keeping raw strings, for two reasons. First, 'feed()' and 'pull()' sit on
the hot path (one call per packet), so wrapping every datagram in an object
adds allocation for what is essentially a byte buffer. Second, binary I/O
across PHP (fread/fwrite, the socket and stream functions, the openssl_*
functions) is consistently done with strings, so a datagram object would be
a bit of an outlier; PHP strings already are the byte-buffer type. I'm open
if there's a concrete benefit I'm missing, for example carrying metadata
alongside the bytes.
On direction: Jakub suggested also exposing a 'dtls://' stream wrapper
alongside the low-level engine, which I think is a good idea. I'm waiting
for his feedback on that before settling the overall shape. Your points
apply to the engine/class surface either way, and I'll fold the agreed ones
in.
Thanks again for the careful read.
Gianfrancesco
Il giorno mer 24 giu 2026 alle ore 23:08 Rowan Tommins [IMSoP] <
[email protected]> ha scritto:
> Hi Gianfrancesco,
>
> I don't have any expertise of the actual protocol, but do have an opinion
> on the PHP surface design. I apologise if the below feels too much like
> bikeshedding...
>
>
> On 24 June 2026 12:45:05 BST, Gianfrancesco Aurecchia <
> [email protected]> wrote:
> > Should the constructor also accept
> > OpenSSLCertificate/OpenSSLAsymmetricKey
> > objects in addition to PEM?
>
> I would say *instead of* a string. Accepting a string means the
> constructor has to document the expected format, produce appropriate parse
> errors, etc; accepting an object reduces that to a standard type check. And
> if the user already has an object, serialising it and then reparsing it is
> duplicated effort.
>
> In general, I would prefer a design which used "real" types throughout
> instead of strings and ints, except where performance is critical:
>
>
> > public const int HANDSHAKE_ERROR = -1;
> > public const int HANDSHAKE_CONTINUE = 0;
> > public const int HANDSHAKE_FINISHED = 1;
>
>
> These should be cases on an enum; probably unbacked, unless there's some
> reason applications need to work with these integer codes.
>
>
> > public function getFingerprint(?string $digestAlgo = null): string
>
>
> Perhaps the supported algorithms could be an enum as well, backed by
> string.
>
>
> > public function feed(string $datagram): int {}
> > public function pull(): ?string {}
>
>
> If $datagram has to be in a specific format, would a lightweight
> DtlsDatagram object be useful? Again, it would delegate the
> parsing/validation to a specific factory, and give flexibility for extra
> ways of creating or reusing material without going via strings and
> revalidating.
>
>
> > public function read(): string|false {}
> > public function exportKeys(string $label, int $length):
> >string|false {}
>
>
> If the false case here is an expected condition, like EOF, "?string" might
> be better. If it's just a signal for unexpected errors, throwing an
> exception would be better.
>
>
> Hopefully someone with more knowledge of the problem space can comment
> more on the core idea.
>
> Thanks,
>
> Rowan Tommins
> [IMSoP]
>