[DOC-CVS] [doc-en] master: Revise the Yaconf extension documentation (#5801)

[email protected] (Xinchen Hui via GitHub)
Newsgroups php.doc.cvs
Message-ID <[email protected]>
Author: Xinchen Hui (laruence)
Committer: GitHub (web-flow)
Pusher: lacatoire
Date: 2026-08-26T11:55:26+02:00

Commit: https://github.com/php/doc-en/commit/3b052562d228be18fa6dce221df7e375469fb7ad
Raw diff: https://github.com/php/doc-en/commit/3b052562d228be18fa6dce221df7e375469fb7ad.diff

Revise the Yaconf extension documentation (#5801)

* Rewrite the Yaconf class documentation with up-to-date method
  signatures, including the previously undocumented __debug_info()
  method added in 1.2.0
* Document the Yaconf 1.2.0 features: compact block storage,
  sub-directory support and ZTS reloading behaviour
* Add installation instructions for PECL, PIE and building from
  source, and mention the security benefit of storing configuration
  files outside the web root
* Move the INI file examples next to the yaconf.directory
  description and give the example file names and keys meaningful
  names
* Register __debug_info in versions.xml

Changed paths:
  A  reference/yaconf/yaconf/debuginfo.xml
  M  reference/yaconf/book.xml
  M  reference/yaconf/ini.xml
  M  reference/yaconf/setup.xml
  M  reference/yaconf/versions.xml
  M  reference/yaconf/yaconf/get.xml
  M  reference/yaconf/yaconf/has.xml


Diff:

diff --git a/reference/yaconf/book.xml b/reference/yaconf/book.xml
index 95faae6e3260..d968aafa7a96 100644
--- a/reference/yaconf/book.xml
+++ b/reference/yaconf/book.xml
@@ -8,65 +8,56 @@
 
  <preface xml:id="intro.yaconf">
   &reftitle.intro;
-  <para>
+  <simpara>
    <literal>Yet Another Configurations Container</literal>
-   (<acronym>Yaconf</acronym>) is a configurations container,
-   it parses <literal>INI</literal> files, and store the result
-   in PHP when PHP is started, the result lives with the
-   whole PHP lifecycle.
-  </para>
-  <para>
-   Yaconf stores all configurations as
-   interned string or immutable array, which means they are
-   not refcounted-able, thus when you retrieving configurations
-   from <acronym>Yaconf</acronym>, it could be considered as zero-copy, very fast.
-  </para>
-  <para>
-   Yaconf supports sections and sections
-   inheritance in <literal>INI</literal> files. If PHP is built as non-ZTS build,
-   Yaconf also supports automatically reloading after <literal>INI</literal> files
-   are changed.
-  </para>
-  <para>
+   (<acronym>Yaconf</acronym>) is a configuration container. It parses
+   <literal>INI</literal> files when PHP starts up and keeps the result
+   in persistent memory for the whole PHP lifecycle, so every retrieval
+   is a fast hash lookup with no file I/O and no per-request parsing.
+  </simpara>
+  <simpara>
+   Yaconf stores all configurations as interned strings or immutable
+   arrays. They are not refcounted, so retrieving a configuration from
+   Yaconf is effectively zero-copy. Since Yaconf 1.2.0, the whole parsed
+   configuration tree is additionally compacted into a single contiguous
+   block, which lowers memory overhead and improves cache locality.
+  </simpara>
+  <simpara>
+   The parsed configuration lives in persistent memory shared by all
+   PHP-FPM workers through copy-on-write: until a configuration file
+   changes, the workers share the same physical memory pages no matter
+   how many of them are running.
+  </simpara>
+  <simpara>
+   Yaconf supports sections and section inheritance in INI files. On
+   non-ZTS builds it also reloads the files automatically when they
+   change; on ZTS (thread-safe) builds, configurations are loaded at
+   startup and a restart is required to pick up changes.
+  </simpara>
+  <simpara>
+   Since Yaconf 1.2.0, sub-directories of the configured directory are
+   loaded recursively (up to 16 levels deep) and addressed with the
+   directory name as a key level: for example,
+   <literal>Yaconf::get("users.database.master")</literal> reads the
+   <literal>master</literal> key from the file
+   <filename>database.ini</filename> placed in the
+   <filename>users/</filename> sub-directory.
+  </simpara>
+  <simpara>
+   Storing sensitive configurations outside the web tree also lowers
+   the attack surface. Configuration files under the web root can be
+   retrieved by an attacker, for example through a file disclosure
+   vulnerability. With Yaconf, the <filename>.ini</filename> files can
+   instead be placed in a directory readable only by root, such as
+   <filename>/etc/yaconf</filename>: the PHP-FPM master loads the
+   configurations when the service starts, while the forked workers —
+   which run under an unprivileged user and are the ones executing
+   web requests — do not need, and are not given, access to that
+   directory.
+  </simpara>
+  <simpara>
    Yaconf requires PHP 7.0 or greater.
-  </para>
-  <example>
-   <title>INI example</title>
-   <programlisting role="ini">
-<![CDATA[
-;Simple key val
-key=val
-
-;Hash
-hash.a=val
-
-;Array
-arr.0=val
-;or
-arr[]=val
-
-;PHP constant
-version=PHP_VERSION
-
-;Environment variable
-env=${PATH}
-]]>
-   </programlisting>
-  </example>
-  <example>
-   <title>INI sections example</title>
-   <programlisting role="ini">
-<![CDATA[
-[SectionA]
-key=val
-hash.a=val
-
-;SectionB inherits SectionA
-[SectionB:SectionA]
-key=new_val                  ;override configuration key in SectionA
-]]>
-   </programlisting>
-  </example>
+  </simpara>
  </preface>
 
  &reference.yaconf.setup;
diff --git a/reference/yaconf/ini.xml b/reference/yaconf/ini.xml
index c82e30adddfb..420d19f5badd 100644
--- a/reference/yaconf/ini.xml
+++ b/reference/yaconf/ini.xml
@@ -18,14 +18,14 @@
     </thead>
     <tbody>
      <row>
-      <entry><link linkend="ini.yaconf.check-delay">yaconf.check_delay</link></entry>
-      <entry>300</entry>
+      <entry><link linkend="ini.yaconf.directory">yaconf.directory</link></entry>
+      <entry><literal>""</literal></entry>
       <entry><constant>INI_SYSTEM</constant></entry>
       <entry><!-- leave empty, this will be filled by an automatic script --></entry>
      </row>
      <row>
-      <entry><link linkend="ini.yaconf.directory">yaconf.directory</link></entry>
-      <entry>/tmp/conf/</entry>
+      <entry><link linkend="ini.yaconf.check-delay">yaconf.check_delay</link></entry>
+      <entry><literal>300</literal></entry>
       <entry><constant>INI_SYSTEM</constant></entry>
       <entry><!-- leave empty, this will be filled by an automatic script --></entry>
      </row>
@@ -38,30 +38,87 @@
 
  <para>
   <variablelist>
-   <varlistentry xml:id="ini.yaconf.check-delay">
+   <varlistentry xml:id="ini.yaconf.directory">
      <term>
-      <parameter>yaconf.check_delay</parameter>
-      <type>int</type>
+      <parameter>yaconf.directory</parameter>
+      <type>string</type>
      </term>
      <listitem>
-      <para>
-        In which interval Yaconf will detect ini file's change(by directory's mtime),
-        if it is set to zero, you have to restart php to reloading configurations.
-      </para>
+      <simpara>
+       The directory where all INI configuration files are placed. Only
+       files with the <filename>.ini</filename> extension are loaded.
+       Sub-directories are loaded recursively (up to 16 levels deep);
+       each one acts as a key level, so a file
+       <filename>database.ini</filename> placed in the
+       <filename>users/</filename> sub-directory is addressed as
+       <literal>"users.database"</literal>. Available since Yaconf
+       1.2.0; before that only files directly in the directory were
+       loaded.
+      </simpara>
+      <simpara>
+       The examples below assume the following
+       <filename>database.ini</filename> placed in the configured
+       directory, alongside a <filename>features.ini</filename> that
+       carries per-feature settings.
+      </simpara>
+      <example>
+       <title>INI file syntax</title>
+       <programlisting role="ini">
+<![CDATA[
+; database.ini
+name=production                        ; scalar value
+version=PHP_VERSION                    ; PHP constants are resolved
+connection_string=${DATABASE_URL}      ; environment variables are resolved
+options.max_connections=50             ; nested hash key
+options.timeout=30
+
+; array entries, both notations are equivalent
+replicas.0=replica-1.example.com
+replicas[]=replica-2.example.com
+]]>
+       </programlisting>
+      </example>
+      <example>
+       <title>INI sections example</title>
+       <programlisting role="ini">
+<![CDATA[
+; features.ini
+[default]
+cache_enabled=on
+rate_limit=100
+
+; the "premium" section inherits every key from "default" and
+; overrides the ones it redefines
+[premium:default]
+rate_limit=1000
+]]>
+       </programlisting>
+      </example>
      </listitem>
-    </varlistentry>
-    <varlistentry xml:id="ini.yaconf.directory">
+   </varlistentry>
+   <varlistentry xml:id="ini.yaconf.check-delay">
      <term>
-      <parameter>yaconf.directory</parameter>
-      <type>string</type>
+      <parameter>yaconf.check_delay</parameter>
+      <type>int</type>
      </term>
      <listitem>
-      <para>
-        Path to directory which all INI configuration files are placed in.
-      </para>
+      <simpara>
+       The interval, in seconds, at which Yaconf checks whether any
+       loaded INI file has changed and reloads the changed ones (the
+       change is detected by comparing directory modification times).
+       Setting it to <literal>0</literal> makes Yaconf check on every
+       request.
+      </simpara>
+      <note>
+       <simpara>
+        This directive is only registered in non-ZTS builds. On ZTS
+        (thread-safe) builds configurations are loaded at startup and
+        automatic reloading is not available; restart PHP to pick up
+        changes.
+       </simpara>
+      </note>
      </listitem>
-    </varlistentry>
-
+   </varlistentry>
   </variablelist>
  </para>
 </section>
diff --git a/reference/yaconf/setup.xml b/reference/yaconf/setup.xml
index cc93a26ae1b3..9a9d5d6d8d64 100644
--- a/reference/yaconf/setup.xml
+++ b/reference/yaconf/setup.xml
@@ -13,6 +13,10 @@
 
  <section xml:id="yaconf.installation">
   &reftitle.install;
+  <simpara>
+   Yaconf can be installed in one of three ways: via PECL, via PIE,
+   or by building it from source.
+  </simpara>
   <para>
    &pecl.moved;
   </para>
@@ -23,6 +27,44 @@
   <para>
    &pecl.windows.download.avail;
   </para>
+  <example>
+   <title>Installing Yaconf with PECL</title>
+   <programlisting role="shell">
+<![CDATA[
+pecl install yaconf
+]]>
+   </programlisting>
+  </example>
+  <simpara>
+   Since Yaconf 1.2.0, the extension can be installed with
+   &link.pie;, the PHP Installer for Extensions, by running the
+   following on the command line.
+  </simpara>
+  <example>
+   <title>Installing Yaconf with PIE</title>
+   <programlisting role="shell">
+<![CDATA[
+pie install laruence/yaconf
+]]>
+   </programlisting>
+  </example>
+  <simpara>
+   The source code is hosted on
+   <link xlink:href="&url.git.hub;laruence/yaconf">GitHub</link>. To
+   build the extension from source, run the following on the command
+   line, replacing the paths with those of the local PHP
+   installation.
+  </simpara>
+  <example>
+   <title>Building Yaconf from source</title>
+   <programlisting role="shell">
+<![CDATA[
+/path/to/phpize
+./configure --with-php-config=/path/to/php-config
+make && make install
+]]>
+   </programlisting>
+  </example>
  </section>
 
  &reference.yaconf.ini;
diff --git a/reference/yaconf/versions.xml b/reference/yaconf/versions.xml
index 77e39928cd51..be012b6fd8a3 100644
--- a/reference/yaconf/versions.xml
+++ b/reference/yaconf/versions.xml
@@ -7,6 +7,7 @@
  <function name='yaconf' from='PECL yaconf &gt;= 1.0.0'/>
  <function name='yaconf::get' from='PECL yaconf &gt;= 1.0.0'/>
  <function name='yaconf::has' from='PECL yaconf &gt;= 1.0.0'/>
+ <function name='yaconf::__debug_info' from='PECL yaconf &gt;= 1.1.0'/>
 </versions>
 
 <!-- Keep this comment at the end of the file
diff --git a/reference/yaconf/yaconf/debuginfo.xml b/reference/yaconf/yaconf/debuginfo.xml
new file mode 100644
index 000000000000..834810185cf0
--- /dev/null
+++ b/reference/yaconf/yaconf/debuginfo.xml
@@ -0,0 +1,144 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- $Revision$ -->
+
+<refentry xml:id="yaconf.debug-info" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
+ <refnamediv>
+  <refname>Yaconf::__debug_info</refname>
+  <refpurpose>Inspect how a configuration value is stored</refpurpose>
+ </refnamediv>
+
+ <refsect1 role="description">
+  &reftitle.description;
+  <methodsynopsis>
+   <modifier>public</modifier> <modifier>static</modifier> <type class="union"><type>array</type><type>null</type></type><methodname>Yaconf::__debug_info</methodname>
+   <methodparam><type>string</type><parameter>name</parameter></methodparam>
+  </methodsynopsis>
+  <simpara>
+   Returns debugging information about the value stored under
+   <parameter>name</parameter>: the memory address of the stored value
+   and whether the value still lives inside Yaconf's compacted storage
+   block.
+  </simpara>
+  <warning>
+   <simpara>
+    This method exists solely for Yaconf's own test suite, which
+    uses it to verify that the extension is working correctly.
+    Do not use it in production code, and do not rely on the
+    format of its output: the returned array may change at any
+    time.
+   </simpara>
+  </warning>
+ </refsect1>
+
+ <refsect1 role="parameters">
+  &reftitle.parameters;
+  <variablelist>
+   <varlistentry>
+    <term><parameter>name</parameter></term>
+    <listitem>
+     <simpara>
+      The configuration name to inspect, using the same dot notation as
+      <methodname>Yaconf::get</methodname>.
+     </simpara>
+    </listitem>
+   </varlistentry>
+  </variablelist>
+ </refsect1>
+
+ <refsect1 role="returnvalues">
+  &reftitle.returnvalues;
+  <simpara>
+   An <type>array</type> with four entries when the configuration
+   exists, &null; otherwise:
+  </simpara>
+  <itemizedlist>
+   <listitem>
+    <simpara>
+     <literal>key</literal> — the name that was looked up.
+    </simpara>
+   </listitem>
+   <listitem>
+    <simpara>
+     <literal>address</literal> — the memory address of the stored
+     value. Values are stored as interned strings or immutable arrays,
+     so this address stays constant until the configuration is
+     reloaded.
+    </simpara>
+   </listitem>
+   <listitem>
+    <simpara>
+     <literal>val</literal> — the stored value itself.
+    </simpara>
+   </listitem>
+   <listitem>
+    <simpara>
+     <literal>changed</literal> — &false; while the value's data still
+     lives inside the compacted storage block, meaning the operating
+     system has not had to copy the page (copy-on-write still applies);
+     &true; when the value has been re-allocated outside the block.
+    </simpara>
+   </listitem>
+  </itemizedlist>
+ </refsect1>
+
+ <refsect1 role="examples">
+  &reftitle.examples;
+  <example>
+   <title><methodname>Yaconf::__debug_info</methodname> example</title>
+   <programlisting role="php">
+<![CDATA[
+<?php
+// assuming app.ini contains name="shop"
+var_dump(Yaconf::__debug_info("app.name"));
+/*
+array(4) {
+  ["key"]=>
+  string(8) "app.name"
+  ["address"]=>
+  string(14) "0x7f8b1c0a3d20"
+  ["val"]=>
+  string(4) "shop"
+  ["changed"]=>
+  bool(false)
+}
+*/
+
+var_dump(Yaconf::__debug_info("app.missing")); // NULL
+?>
+]]>
+   </programlisting>
+  </example>
+ </refsect1>
+
+ <refsect1 role="seealso">
+  &reftitle.seealso;
+  <para>
+   <simplelist>
+    <member><methodname>Yaconf::get</methodname></member>
+    <member><methodname>Yaconf::has</methodname></member>
+   </simplelist>
+  </para>
+ </refsect1>
+
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:t
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:1
+sgml-indent-data:t
+indent-tabs-mode:nil
+sgml-parent-document:nil
+sgml-default-dtd-file:"~/.phpdoc/manual.ced"
+sgml-exposed-tags:nil
+sgml-local-catalogs:nil
+sgml-local-ecat-files:nil
+End:
+vim600: syn=xml fen fdm=syntax fdl=2 si
+vim: et tw=78 syn=sgml
+vi: ts=1 sw=1
+-->
diff --git a/reference/yaconf/yaconf/get.xml b/reference/yaconf/yaconf/get.xml
index bda9b673e7cf..9cbbd4e062f0 100644
--- a/reference/yaconf/yaconf/get.xml
+++ b/reference/yaconf/yaconf/get.xml
@@ -4,7 +4,7 @@
 <refentry xml:id="yaconf.get" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
  <refnamediv>
   <refname>Yaconf::get</refname>
-  <refpurpose>Retrieve a item</refpurpose>
+  <refpurpose>Retrieve a configuration value by name</refpurpose>
  </refnamediv>
 
  <refsect1 role="description">
@@ -12,11 +12,19 @@
   <methodsynopsis>
    <modifier>public</modifier> <modifier>static</modifier> <type>mixed</type><methodname>Yaconf::get</methodname>
    <methodparam><type>string</type><parameter>name</parameter></methodparam>
-   <methodparam choice="opt"><type>mixed</type><parameter>default_value</parameter><initializer>NULL</initializer></methodparam>
+   <methodparam choice="opt"><type>mixed</type><parameter>default</parameter><initializer>&null;</initializer></methodparam>
   </methodsynopsis>
-  <para>
-
-  </para>
+  <simpara>
+   Retrieves the configuration value stored under
+   <parameter>name</parameter>. Names use dot notation to traverse
+   nested keys: <literal>"app"</literal> addresses the whole parsed
+   <filename>app.ini</filename> file,
+   <literal>"app.name"</literal> a key inside it, and since Yaconf
+   1.2.0 <literal>"users.database.master"</literal> a key in the
+   file <filename>database.ini</filename> placed in the
+   <filename>users/</filename> sub-directory. The dot notation
+   supports up to 64 levels of nesting.
+  </simpara>
  </refsect1>
 
  <refsect1 role="parameters">
@@ -25,17 +33,22 @@
    <varlistentry>
     <term><parameter>name</parameter></term>
     <listitem>
-     <para>
-      Configuration key, the key looks like "filename.key", or "filename.sectionName,key".
-     </para>
+     <simpara>
+      The configuration name to look up, using dot notation to
+      traverse nested keys, for example
+      <literal>"app.name"</literal>, <literal>"app.features.1"</literal>
+      or, since Yaconf 1.2.0, <literal>"users.database.master"</literal>
+      for files in sub-directories.
+     </simpara>
     </listitem>
    </varlistentry>
    <varlistentry>
-    <term><parameter>default_value</parameter></term>
+    <term><parameter>default</parameter></term>
     <listitem>
-     <para>
-      if the key doesn't exists, Yaconf::get will return this as result.
-     </para>
+     <simpara>
+      The value to return when <parameter>name</parameter> is not
+      found. When omitted, &null; is returned.
+     </simpara>
     </listitem>
    </varlistentry>
   </variablelist>
@@ -43,52 +56,71 @@
 
  <refsect1 role="returnvalues">
   &reftitle.returnvalues;
-  <para>
-   Returns configuration result(string or array) if the key exists,
-   return default_value if not.
-  </para>
+  <simpara>
+   The stored configuration value, a <type>string</type> or an
+   <type>array</type>, when <parameter>name</parameter> exists;
+   otherwise the <parameter>default</parameter> (or &null; when no
+   default was given).
+  </simpara>
  </refsect1>
 
  <refsect1 role="examples">
   &reftitle.examples;
-  <example>
-   <title><function>INI</function>example</title>
-   <programlisting role="ini">
+  <simpara>
+   The examples below assume the following two files placed in the
+   directory configured with <literal>yaconf.directory</literal>.
+  </simpara>
+  <programlisting role="ini">
 <![CDATA[
-;filenmame foo.ini, placed in directory which is yaconf.directoy
-[SectionA]
-;key value pair
-key=val
-;hash[a]=val
-hash.a=val
-;arr[0]=val
-arr.0=val
-;or
-arr[]=val
-
-;SectionB inherits SectionA
-[SectionB:SectionA]
-;override configuration key in SectionA
-key=new_val
+; app.ini
+name="shop"                     ; scalar value
+debug=0                         ; number
+features[]="checkout"           ; array entries, both notations
+features.1="wishlist"
 ]]>
-   </programlisting>
-   &example.outputs.similar;
-   <screen>
+  </programlisting>
+  <programlisting role="ini">
 <![CDATA[
-php7 -r 'var_dump(Yaconf::get("foo.SectionA.key"));'
-//string(3) "val"
+; users/database.ini, in a sub-directory (Yaconf 1.2.0+)
+master="192.168.0.10"
+replica="192.168.0.20"
+]]>
+  </programlisting>
+  <example>
+   <title><methodname>Yaconf::get</methodname> example</title>
+   <programlisting role="php">
+<![CDATA[
+<?php
+// fetch a whole parsed file as an array
+var_dump(Yaconf::get("app"));
 
-php7 -r 'var_dump(Yaconf::get("foo.SectionB.key"));'
-//string(7) "new_val"
+// dot notation traverses nested keys
+var_dump(Yaconf::get("app.name"));           // string(4) "shop"
+var_dump(Yaconf::get("app.features.1"));     // string(8) "wishlist"
 
-php7 -r 'var_dump(Yaconf::get("foo")["SectionA"]["hash"]);'
-//array(1)
+// since 1.2.0: files in sub-directories are namespaced by the
+// directory name
+var_dump(Yaconf::get("users.database.master")); // string(12) "192.168.0.10"
 
+// when the key is missing, the default is returned
+var_dump(Yaconf::get("app.missing"));             // NULL
+var_dump(Yaconf::get("app.missing", "fallback")); // string(8) "fallback"
+?>
 ]]>
-   </screen>
+   </programlisting>
   </example>
  </refsect1>
 
+ <refsect1 role="seealso">
+  &reftitle.seealso;
+  <para>
+   <simplelist>
+    <member><methodname>Yaconf::has</methodname></member>
+    <member><methodname>Yaconf::__debug_info</methodname></member>
+   </simplelist>
+  </para>
+ </refsect1>
+
 </refentry>
 
 <!-- Keep this comment at the end of the file
diff --git a/reference/yaconf/yaconf/has.xml b/reference/yaconf/yaconf/has.xml
index 60fd002989ba..8a77ab7974ff 100644
--- a/reference/yaconf/yaconf/has.xml
+++ b/reference/yaconf/yaconf/has.xml
@@ -4,7 +4,7 @@
 <refentry xml:id="yaconf.has" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
  <refnamediv>
   <refname>Yaconf::has</refname>
-  <refpurpose>Determine if a item exists</refpurpose>
+  <refpurpose>Check whether a configuration value exists</refpurpose>
  </refnamediv>
 
  <refsect1 role="description">
@@ -13,9 +13,13 @@
    <modifier>public</modifier> <modifier>static</modifier> <type>bool</type><methodname>Yaconf::has</methodname>
    <methodparam><type>string</type><parameter>name</parameter></methodparam>
   </methodsynopsis>
-  <para>
-
-  </para>
+  <simpara>
+   Determines whether a configuration value exists under
+   <parameter>name</parameter>, which uses the same dot notation as
+   <methodname>Yaconf::get</methodname>: for example, <literal>"app.name"</literal>
+   or, since Yaconf 1.2.0, <literal>"users.database.master"</literal> for
+   files in sub-directories.
+  </simpara>
  </refsect1>
 
  <refsect1 role="parameters">
@@ -24,9 +28,11 @@
    <varlistentry>
     <term><parameter>name</parameter></term>
     <listitem>
-     <para>
-      
-     </para>
+     <simpara>
+      The configuration name to look up, using dot notation to
+      traverse nested keys, for example <literal>"app.name"</literal>
+      or <literal>"users.database.master"</literal>.
+     </simpara>
     </listitem>
    </varlistentry>
   </variablelist>
@@ -34,12 +40,49 @@
 
  <refsect1 role="returnvalues">
   &reftitle.returnvalues;
+  <simpara>
+   Returns &true; if a configuration value exists at
+   <parameter>name</parameter>, &false; otherwise.
+  </simpara>
+ </refsect1>
+
+ <refsect1 role="examples">
+  &reftitle.examples;
+  <simpara>
+   The examples below assume an <filename>app.ini</filename> placed
+   in the directory configured with <literal>yaconf.directory</literal>,
+   holding the keys <literal>name="shop"</literal> and
+   <literal>debug=0</literal>.
+  </simpara>
+  <example>
+   <title><methodname>Yaconf::has</methodname> example</title>
+   <programlisting role="php">
+<![CDATA[
+<?php
+var_dump(Yaconf::has("app.name"));     // bool(true)
+var_dump(Yaconf::has("app.missing"));  // bool(false)
+
+// useful to distinguish a stored empty value from a missing key,
+// where Yaconf::get() would return the same default for both
+if (Yaconf::has("app.debug")) {
+    $debug = (bool) Yaconf::get("app.debug");
+}
+?>
+]]>
+   </programlisting>
+  </example>
+ </refsect1>
+
+ <refsect1 role="seealso">
+  &reftitle.seealso;
   <para>
-   
+   <simplelist>
+    <member><methodname>Yaconf::get</methodname></member>
+    <member><methodname>Yaconf::__debug_info</methodname></member>
+   </simplelist>
   </para>
  </refsect1>
 
-
 </refentry>
 
 <!-- Keep this comment at the end of the file
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.