It is common for a system or a program to have a config file: that is a file that holds a bunch of settings that can be adjusted by the administrator or user to get desired effect. A code module, that is designed to be embedded into a running program and is designed to be reused in multiple programs, should NEVER require a configuration file.
A reusable module is a collection of code that can be embedded into a program. The module is designed to perform a function, and should not impact the containing program in any way more than absolutely necessary. The module must have very clear inputs and outputs — and that is usually the case. The module is designed to be controlled by something else: by the containing program. That program might be an Applet embedded in a browser, an installed user program, a server installed as a Windows service, or any number of other possible environments. The key here is that for a module to be used in as many environments as possible, it should not make any assumptions about the environment that it will be running in.
A module may be configurable, meaning that it runs in a number of modes which can be selected ahead of time by some form of configuration parameters. There should be clear API methods for setting the mode of the module: certain features and capabilities might be turned on or off. The API to the module is king, and it should be in complete control of the mode that the module runs in.
The containing program might have a config file, and that is completely acceptable, because the containing program is designed for a specific environment. Some programs keep their configuration in a DB. Some fetch their configuration from a web service. There are an infinite variety of ways to store the configuration of a program. Even if there is a regular configuration file, there is a lot of variation around where that file is stored, in order to make management of the system easier for the administrator.
Such a module should never attempt to read a configuration file in order to get these config settings. It should not assume that it has access to the file system. Even if the purpose of the module is to access the file system, it still might not have access to the part of the file systems that one would normally store configuration information.
Creating a module that has its own config file can be a big complication to the system. If the containing program wants to be smart and auto-detect some of these parameters, it would then need to write out the config file for the module, and this is considerably more complicated than calling a method. If the containing programs want the configuration information to be in a special place the module might not be prepared for this. Consider a program that is multi-user and wants different configuration for each user. It is unlikely the module would be prepared to meet these conditions if it has its own config file.
Consider a program that has 20 modules in use. If each had its own config file, that is 20 separate files to be maintained. What is worse, is that there are doubtless many duplicated values in these 20 files. Or even worse, there may be values that are not exactly the same, but have to be kept in some complicated relationship to each other. The documentation on how all these configuration parameters must be keep in synch is not only a big job, but puts a big burden on the administrator. It should also be obvious that the more way to configure a system incorrectly, the more chance to configure incorrectly, the more bugs that the user is going to run into.
The module is controlled by API method calls. If the module requires settings, then the controlling program should call a method on the module, in order to set it up. It could be a single method where you pass in an associative array, or it could be separate methods for each possible setting. It does not really matter, because as long as it is method calls, the containing program can be written to configure the module correctly.
If there are a lot of settings, and it is likely that the module will be configured separately from the rest of the program, then the containing program should be in charge of reading the file into an appropriate in memory structure,and then passed as an associative array to the module. Or the module might offer a method to initialize itself from a file, and the exact file path is passed in from the controlling program. All of these are acceptable because the containing program has complete control over the configuration of the module.
What is absolutely prohibited, is for a module to transparently read a file on demand (using lazy initialization) when needed from an unannounced location initializing itself. This kind of module can only be used in special situations where the assumed environment matches the actual environment, and such modules cause more problems for the containing program than it is worth.